17c478bd9Sstevel@tonic-gate /*
2*d4204c85Sraf  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
37c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
47c478bd9Sstevel@tonic-gate  */
57c478bd9Sstevel@tonic-gate 
67c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
77c478bd9Sstevel@tonic-gate 
87c478bd9Sstevel@tonic-gate 
97c478bd9Sstevel@tonic-gate /*
107c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the Netscape Public
117c478bd9Sstevel@tonic-gate  * License Version 1.1 (the "License"); you may not use this file
127c478bd9Sstevel@tonic-gate  * except in compliance with the License. You may obtain a copy of
137c478bd9Sstevel@tonic-gate  * the License at http://www.mozilla.org/NPL/
147c478bd9Sstevel@tonic-gate  *
157c478bd9Sstevel@tonic-gate  * Software distributed under the License is distributed on an "AS
167c478bd9Sstevel@tonic-gate  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
177c478bd9Sstevel@tonic-gate  * implied. See the License for the specific language governing
187c478bd9Sstevel@tonic-gate  * rights and limitations under the License.
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * The Original Code is Mozilla Communicator client code, released
217c478bd9Sstevel@tonic-gate  * March 31, 1998.
227c478bd9Sstevel@tonic-gate  *
237c478bd9Sstevel@tonic-gate  * The Initial Developer of the Original Code is Netscape
247c478bd9Sstevel@tonic-gate  * Communications Corporation. Portions created by Netscape are
257c478bd9Sstevel@tonic-gate  * Copyright (C) 1998-1999 Netscape Communications Corporation. All
267c478bd9Sstevel@tonic-gate  * Rights Reserved.
277c478bd9Sstevel@tonic-gate  *
287c478bd9Sstevel@tonic-gate  * Contributor(s):
297c478bd9Sstevel@tonic-gate  */
307c478bd9Sstevel@tonic-gate 
317c478bd9Sstevel@tonic-gate /*
327c478bd9Sstevel@tonic-gate  * Thread callback functions for libldap that use the NSPR (Netscape
337c478bd9Sstevel@tonic-gate  * Portable Runtime) thread API.
347c478bd9Sstevel@tonic-gate  *
357c478bd9Sstevel@tonic-gate  */
367c478bd9Sstevel@tonic-gate 
377c478bd9Sstevel@tonic-gate #ifdef _SOLARIS_SDK
387c478bd9Sstevel@tonic-gate #include <thread.h>
397c478bd9Sstevel@tonic-gate #include <synch.h>
407c478bd9Sstevel@tonic-gate #include <prinit.h>
417c478bd9Sstevel@tonic-gate #include <prthread.h>
427c478bd9Sstevel@tonic-gate #include <syslog.h>
437c478bd9Sstevel@tonic-gate #include <string.h>
447c478bd9Sstevel@tonic-gate #include <sys/types.h>
457c478bd9Sstevel@tonic-gate #include <signal.h>
467c478bd9Sstevel@tonic-gate #include <errno.h>
477c478bd9Sstevel@tonic-gate extern int	errno;
487c478bd9Sstevel@tonic-gate #endif	/* _SOLARIS_SDK */
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate #include "ldappr-int.h"
517c478bd9Sstevel@tonic-gate 
527c478bd9Sstevel@tonic-gate #ifndef _SOLARIS_SDK
537c478bd9Sstevel@tonic-gate /*
547c478bd9Sstevel@tonic-gate  * Macros:
557c478bd9Sstevel@tonic-gate  */
567c478bd9Sstevel@tonic-gate /*
577c478bd9Sstevel@tonic-gate  * Grow thread private data arrays 10 elements at a time.
587c478bd9Sstevel@tonic-gate  */
597c478bd9Sstevel@tonic-gate #define PRLDAP_TPD_ARRAY_INCREMENT	10
607c478bd9Sstevel@tonic-gate 
617c478bd9Sstevel@tonic-gate /*
627c478bd9Sstevel@tonic-gate  * Structures and types:
637c478bd9Sstevel@tonic-gate  */
647c478bd9Sstevel@tonic-gate /*
657c478bd9Sstevel@tonic-gate  * Structure used by libldap thread callbacks to maintain error information.
667c478bd9Sstevel@tonic-gate  */
677c478bd9Sstevel@tonic-gate typedef struct prldap_errorinfo {
687c478bd9Sstevel@tonic-gate     int		plei_lderrno;
697c478bd9Sstevel@tonic-gate     char	*plei_matched;
707c478bd9Sstevel@tonic-gate     char	*plei_errmsg;
717c478bd9Sstevel@tonic-gate } PRLDAP_ErrorInfo;
727c478bd9Sstevel@tonic-gate 
737c478bd9Sstevel@tonic-gate /*
747c478bd9Sstevel@tonic-gate  * Structure used to maintain thread-private data. At the present time,
757c478bd9Sstevel@tonic-gate  * only error info. is thread-private.  One of these structures is allocated
767c478bd9Sstevel@tonic-gate  * for each thread.
777c478bd9Sstevel@tonic-gate  */
787c478bd9Sstevel@tonic-gate typedef struct prldap_tpd_header {
797c478bd9Sstevel@tonic-gate     int			ptpdh_tpd_count;	/* # of data items allocated */
807c478bd9Sstevel@tonic-gate     void		**ptpdh_dataitems;	/* array of data items */
817c478bd9Sstevel@tonic-gate } PRLDAP_TPDHeader;
827c478bd9Sstevel@tonic-gate 
837c478bd9Sstevel@tonic-gate /*
847c478bd9Sstevel@tonic-gate  * Structure used by associate a PRLDAP thread-private data index with an
857c478bd9Sstevel@tonic-gate  * LDAP session handle. One of these exists for each active LDAP session
867c478bd9Sstevel@tonic-gate  * handle.
877c478bd9Sstevel@tonic-gate  */
887c478bd9Sstevel@tonic-gate typedef struct prldap_tpd_map {
897c478bd9Sstevel@tonic-gate     LDAP			*prtm_ld;	/* non-NULL if in use */
907c478bd9Sstevel@tonic-gate     PRUintn			prtm_index;	/* index into TPD array */
917c478bd9Sstevel@tonic-gate     struct prldap_tpd_map	*prtm_next;
927c478bd9Sstevel@tonic-gate } PRLDAP_TPDMap;
937c478bd9Sstevel@tonic-gate 
947c478bd9Sstevel@tonic-gate #ifdef _SOLARIS_SDK
957c478bd9Sstevel@tonic-gate extern  mutex_t         inited_mutex;
967c478bd9Sstevel@tonic-gate #endif  /* _SOLARIS_SDK */
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate /*
997c478bd9Sstevel@tonic-gate  * Static Variables:
1007c478bd9Sstevel@tonic-gate  */
1017c478bd9Sstevel@tonic-gate /*
1027c478bd9Sstevel@tonic-gate  * prldap_map_list points to all of the PRLDAP_TPDMap structures
1037c478bd9Sstevel@tonic-gate  * we have ever allocated.  We recycle them as we open and close LDAP
1047c478bd9Sstevel@tonic-gate  * sessions.
1057c478bd9Sstevel@tonic-gate  */
1067c478bd9Sstevel@tonic-gate static PRLDAP_TPDMap *prldap_map_list = NULL;
1077c478bd9Sstevel@tonic-gate 
1087c478bd9Sstevel@tonic-gate 
1097c478bd9Sstevel@tonic-gate /*
1107c478bd9Sstevel@tonic-gate  * The prldap_map_mutex is used to protect access to the prldap_map_list.
1117c478bd9Sstevel@tonic-gate  */
1127c478bd9Sstevel@tonic-gate static PRLock	*prldap_map_mutex = NULL;
1137c478bd9Sstevel@tonic-gate 
1147c478bd9Sstevel@tonic-gate /*
1157c478bd9Sstevel@tonic-gate  * The prldap_tpd_maxindex value is used to track the largest TPD array
1167c478bd9Sstevel@tonic-gate  * index we have used.
1177c478bd9Sstevel@tonic-gate  */
1187c478bd9Sstevel@tonic-gate static PRInt32	prldap_tpd_maxindex = -1;
1197c478bd9Sstevel@tonic-gate 
1207c478bd9Sstevel@tonic-gate /*
1217c478bd9Sstevel@tonic-gate  * prldap_tpdindex is an NSPR thread private data index we use to
1227c478bd9Sstevel@tonic-gate  * maintain our own thread-private data. It is initialized inside
1237c478bd9Sstevel@tonic-gate  * prldap_init_tpd().
1247c478bd9Sstevel@tonic-gate  */
1257c478bd9Sstevel@tonic-gate static PRUintn	prldap_tpdindex = 0;
1267c478bd9Sstevel@tonic-gate 
1277c478bd9Sstevel@tonic-gate /*
1287c478bd9Sstevel@tonic-gate  * The prldap_callonce_init_tpd structure is used by NSPR to ensure
1297c478bd9Sstevel@tonic-gate  * that prldap_init_tpd() is called at most once.
1307c478bd9Sstevel@tonic-gate  */
1317c478bd9Sstevel@tonic-gate static PRCallOnceType prldap_callonce_init_tpd = { 0, 0, 0 };
1327c478bd9Sstevel@tonic-gate 
1337c478bd9Sstevel@tonic-gate 
1347c478bd9Sstevel@tonic-gate /*
1357c478bd9Sstevel@tonic-gate  * Private function prototypes:
1367c478bd9Sstevel@tonic-gate  */
1377c478bd9Sstevel@tonic-gate static void prldap_set_ld_error( int err, char *matched, char *errmsg,
1387c478bd9Sstevel@tonic-gate 	void *errorarg );
1397c478bd9Sstevel@tonic-gate static int prldap_get_ld_error( char **matchedp, char **errmsgp,
1407c478bd9Sstevel@tonic-gate 	void *errorarg );
1417c478bd9Sstevel@tonic-gate #endif
1427c478bd9Sstevel@tonic-gate static void *prldap_mutex_alloc( void );
1437c478bd9Sstevel@tonic-gate static void prldap_mutex_free( void *mutex );
1447c478bd9Sstevel@tonic-gate static int prldap_mutex_lock( void *mutex );
1457c478bd9Sstevel@tonic-gate static int prldap_mutex_unlock( void *mutex );
1467c478bd9Sstevel@tonic-gate static void *prldap_get_thread_id( void );
1477c478bd9Sstevel@tonic-gate #ifndef _SOLARIS_SDK
1487c478bd9Sstevel@tonic-gate static PRStatus prldap_init_tpd( void );
1497c478bd9Sstevel@tonic-gate static PRLDAP_TPDMap *prldap_allocate_map( LDAP *ld );
1507c478bd9Sstevel@tonic-gate static void prldap_return_map( PRLDAP_TPDMap *map );
1517c478bd9Sstevel@tonic-gate static PRUintn prldap_new_tpdindex( void );
1527c478bd9Sstevel@tonic-gate static int prldap_set_thread_private( PRInt32 tpdindex, void *priv );
1537c478bd9Sstevel@tonic-gate static void *prldap_get_thread_private( PRInt32 tpdindex );
1547c478bd9Sstevel@tonic-gate static PRLDAP_TPDHeader *prldap_tsd_realloc( PRLDAP_TPDHeader *tsdhdr,
1557c478bd9Sstevel@tonic-gate 	int maxindex );
1567c478bd9Sstevel@tonic-gate static void prldap_tsd_destroy( void *priv );
1577c478bd9Sstevel@tonic-gate #endif
1587c478bd9Sstevel@tonic-gate 
1597c478bd9Sstevel@tonic-gate 
1607c478bd9Sstevel@tonic-gate /*
1617c478bd9Sstevel@tonic-gate  * Install NSPR thread functions into ld (if ld is NULL, they are installed
1627c478bd9Sstevel@tonic-gate  * as the default functions for new LDAP * handles).
1637c478bd9Sstevel@tonic-gate  *
1647c478bd9Sstevel@tonic-gate  * Returns 0 if all goes well and -1 if not.
1657c478bd9Sstevel@tonic-gate  */
1667c478bd9Sstevel@tonic-gate int
1677c478bd9Sstevel@tonic-gate prldap_install_thread_functions( LDAP *ld, int shared )
1687c478bd9Sstevel@tonic-gate {
1697c478bd9Sstevel@tonic-gate     struct ldap_thread_fns		tfns;
1707c478bd9Sstevel@tonic-gate     struct ldap_extra_thread_fns	xtfns;
1717c478bd9Sstevel@tonic-gate 
1727c478bd9Sstevel@tonic-gate #ifndef _SOLARIS_SDK
1737c478bd9Sstevel@tonic-gate     if ( PR_CallOnce( &prldap_callonce_init_tpd, prldap_init_tpd )
1747c478bd9Sstevel@tonic-gate 		!= PR_SUCCESS ) {
1757c478bd9Sstevel@tonic-gate 	ldap_set_lderrno( ld, LDAP_LOCAL_ERROR, NULL, NULL );
1767c478bd9Sstevel@tonic-gate 	return( -1 );
1777c478bd9Sstevel@tonic-gate     }
1787c478bd9Sstevel@tonic-gate #endif	/* _SOLARIS_SDK */
1797c478bd9Sstevel@tonic-gate 
1807c478bd9Sstevel@tonic-gate     /* set thread function pointers */
1817c478bd9Sstevel@tonic-gate     memset( &tfns, '\0', sizeof(struct ldap_thread_fns) );
1827c478bd9Sstevel@tonic-gate     tfns.ltf_get_errno = prldap_get_system_errno;
1837c478bd9Sstevel@tonic-gate     tfns.ltf_set_errno = prldap_set_system_errno;
1847c478bd9Sstevel@tonic-gate     if ( shared ) {
1857c478bd9Sstevel@tonic-gate 	tfns.ltf_mutex_alloc = prldap_mutex_alloc;
1867c478bd9Sstevel@tonic-gate 	tfns.ltf_mutex_free = prldap_mutex_free;
1877c478bd9Sstevel@tonic-gate 	tfns.ltf_mutex_lock = prldap_mutex_lock;
1887c478bd9Sstevel@tonic-gate 	tfns.ltf_mutex_unlock = prldap_mutex_unlock;
1897c478bd9Sstevel@tonic-gate #ifdef _SOLARIS_SDK
1907c478bd9Sstevel@tonic-gate 	tfns.ltf_get_lderrno = NULL;
1917c478bd9Sstevel@tonic-gate 	tfns.ltf_set_lderrno = NULL;
1927c478bd9Sstevel@tonic-gate #else
1937c478bd9Sstevel@tonic-gate 	tfns.ltf_get_lderrno = prldap_get_ld_error;
1947c478bd9Sstevel@tonic-gate 	tfns.ltf_set_lderrno = prldap_set_ld_error;
1957c478bd9Sstevel@tonic-gate 	if ( ld != NULL ) {
1967c478bd9Sstevel@tonic-gate 	    /*
1977c478bd9Sstevel@tonic-gate 	     * If this is a real ld (i.e., we are not setting the global
1987c478bd9Sstevel@tonic-gate 	     * defaults) allocate thread private data for error information.
1997c478bd9Sstevel@tonic-gate 	     * If ld is NULL we do not do this here but it is done in
2007c478bd9Sstevel@tonic-gate 	     * prldap_thread_new_handle().
2017c478bd9Sstevel@tonic-gate 	     */
2027c478bd9Sstevel@tonic-gate 	    if (( tfns.ltf_lderrno_arg = (void *)prldap_allocate_map( ld ))
2037c478bd9Sstevel@tonic-gate 		    == NULL ) {
2047c478bd9Sstevel@tonic-gate 		return( -1 );
2057c478bd9Sstevel@tonic-gate 	    }
2067c478bd9Sstevel@tonic-gate 	}
2077c478bd9Sstevel@tonic-gate #endif
2087c478bd9Sstevel@tonic-gate     }
2097c478bd9Sstevel@tonic-gate 
2107c478bd9Sstevel@tonic-gate     if ( ldap_set_option( ld, LDAP_OPT_THREAD_FN_PTRS,
2117c478bd9Sstevel@tonic-gate 	    (void *)&tfns ) != 0 ) {
2127c478bd9Sstevel@tonic-gate #ifndef _SOLARIS_SDK
2137c478bd9Sstevel@tonic-gate 	prldap_return_map( (PRLDAP_TPDMap *)tfns.ltf_lderrno_arg );
2147c478bd9Sstevel@tonic-gate #endif
2157c478bd9Sstevel@tonic-gate 	return( -1 );
2167c478bd9Sstevel@tonic-gate     }
2177c478bd9Sstevel@tonic-gate 
2187c478bd9Sstevel@tonic-gate     /* set extended thread function pointers */
2197c478bd9Sstevel@tonic-gate     memset( &xtfns, '\0', sizeof(struct ldap_extra_thread_fns) );
2207c478bd9Sstevel@tonic-gate     xtfns.ltf_threadid_fn = prldap_get_thread_id;
2217c478bd9Sstevel@tonic-gate     if ( ldap_set_option( ld, LDAP_OPT_EXTRA_THREAD_FN_PTRS,
2227c478bd9Sstevel@tonic-gate 	    (void *)&xtfns ) != 0 ) {
2237c478bd9Sstevel@tonic-gate 	return( -1 );
2247c478bd9Sstevel@tonic-gate     }
2257c478bd9Sstevel@tonic-gate 
2267c478bd9Sstevel@tonic-gate     return( 0 );
2277c478bd9Sstevel@tonic-gate }
2287c478bd9Sstevel@tonic-gate 
2297c478bd9Sstevel@tonic-gate 
2307c478bd9Sstevel@tonic-gate static void *
2317c478bd9Sstevel@tonic-gate prldap_mutex_alloc( void )
2327c478bd9Sstevel@tonic-gate {
2337c478bd9Sstevel@tonic-gate     return( (void *)PR_NewLock());
2347c478bd9Sstevel@tonic-gate }
2357c478bd9Sstevel@tonic-gate 
2367c478bd9Sstevel@tonic-gate 
2377c478bd9Sstevel@tonic-gate static void
2387c478bd9Sstevel@tonic-gate prldap_mutex_free( void *mutex )
2397c478bd9Sstevel@tonic-gate {
2407c478bd9Sstevel@tonic-gate     PR_DestroyLock( (PRLock *)mutex );
2417c478bd9Sstevel@tonic-gate }
2427c478bd9Sstevel@tonic-gate 
2437c478bd9Sstevel@tonic-gate 
2447c478bd9Sstevel@tonic-gate static int
2457c478bd9Sstevel@tonic-gate prldap_mutex_lock( void *mutex )
2467c478bd9Sstevel@tonic-gate {
2477c478bd9Sstevel@tonic-gate     PR_Lock( (PRLock *)mutex );
2487c478bd9Sstevel@tonic-gate     return( 0 );
2497c478bd9Sstevel@tonic-gate }
2507c478bd9Sstevel@tonic-gate 
2517c478bd9Sstevel@tonic-gate 
2527c478bd9Sstevel@tonic-gate static int
2537c478bd9Sstevel@tonic-gate prldap_mutex_unlock( void *mutex )
2547c478bd9Sstevel@tonic-gate {
2557c478bd9Sstevel@tonic-gate     if ( PR_Unlock( (PRLock *)mutex ) == PR_FAILURE ) {
2567c478bd9Sstevel@tonic-gate 	return( -1 );
2577c478bd9Sstevel@tonic-gate     }
2587c478bd9Sstevel@tonic-gate 
2597c478bd9Sstevel@tonic-gate     return( 0 );
2607c478bd9Sstevel@tonic-gate }
2617c478bd9Sstevel@tonic-gate 
2627c478bd9Sstevel@tonic-gate 
2637c478bd9Sstevel@tonic-gate static void *
2647c478bd9Sstevel@tonic-gate prldap_get_thread_id( void )
2657c478bd9Sstevel@tonic-gate {
2667c478bd9Sstevel@tonic-gate #ifdef	_SOLARIS_SDK
2677c478bd9Sstevel@tonic-gate 	return ((void *)thr_self());
2687c478bd9Sstevel@tonic-gate #else
2697c478bd9Sstevel@tonic-gate     return( (void *)PR_GetCurrentThread());
2707c478bd9Sstevel@tonic-gate #endif
2717c478bd9Sstevel@tonic-gate }
2727c478bd9Sstevel@tonic-gate 
2737c478bd9Sstevel@tonic-gate #ifndef	_SOLARIS_SDK
2747c478bd9Sstevel@tonic-gate static int
2757c478bd9Sstevel@tonic-gate prldap_get_ld_error( char **matchedp, char **errmsgp, void *errorarg )
2767c478bd9Sstevel@tonic-gate {
2777c478bd9Sstevel@tonic-gate     PRLDAP_TPDMap	*map;
2787c478bd9Sstevel@tonic-gate     PRLDAP_ErrorInfo	*eip;
2797c478bd9Sstevel@tonic-gate 
2807c478bd9Sstevel@tonic-gate     if (( map = (PRLDAP_TPDMap *)errorarg ) != NULL && ( eip =
2817c478bd9Sstevel@tonic-gate 	    (PRLDAP_ErrorInfo *)prldap_get_thread_private(
2827c478bd9Sstevel@tonic-gate 	    map->prtm_index )) != NULL ) {
2837c478bd9Sstevel@tonic-gate 	if ( matchedp != NULL ) {
2847c478bd9Sstevel@tonic-gate 	    *matchedp = eip->plei_matched;
2857c478bd9Sstevel@tonic-gate 	}
2867c478bd9Sstevel@tonic-gate 	if ( errmsgp != NULL ) {
2877c478bd9Sstevel@tonic-gate 	    *errmsgp = eip->plei_errmsg;
2887c478bd9Sstevel@tonic-gate 	}
2897c478bd9Sstevel@tonic-gate 	return( eip->plei_lderrno );
2907c478bd9Sstevel@tonic-gate     } else {
2917c478bd9Sstevel@tonic-gate 	if ( matchedp != NULL ) {
2927c478bd9Sstevel@tonic-gate 	    *matchedp = NULL;
2937c478bd9Sstevel@tonic-gate 	}
2947c478bd9Sstevel@tonic-gate 	if ( errmsgp != NULL ) {
2957c478bd9Sstevel@tonic-gate 	    *errmsgp = NULL;
2967c478bd9Sstevel@tonic-gate 	}
2977c478bd9Sstevel@tonic-gate 	return( LDAP_LOCAL_ERROR );	/* punt */
2987c478bd9Sstevel@tonic-gate     }
2997c478bd9Sstevel@tonic-gate }
3007c478bd9Sstevel@tonic-gate 
3017c478bd9Sstevel@tonic-gate 
3027c478bd9Sstevel@tonic-gate static void
3037c478bd9Sstevel@tonic-gate prldap_set_ld_error( int err, char *matched, char *errmsg, void *errorarg )
3047c478bd9Sstevel@tonic-gate {
3057c478bd9Sstevel@tonic-gate     PRLDAP_TPDMap	*map;
3067c478bd9Sstevel@tonic-gate     PRLDAP_ErrorInfo	*eip;
3077c478bd9Sstevel@tonic-gate 
3087c478bd9Sstevel@tonic-gate     if (( map = (PRLDAP_TPDMap *)errorarg ) != NULL ) {
3097c478bd9Sstevel@tonic-gate 	if (( eip = (PRLDAP_ErrorInfo *)prldap_get_thread_private(
3107c478bd9Sstevel@tonic-gate 		map->prtm_index )) == NULL ) {
3117c478bd9Sstevel@tonic-gate 	    /*
3127c478bd9Sstevel@tonic-gate 	     * Error info. has not yet been allocated for this thread.
3137c478bd9Sstevel@tonic-gate 	     * Do so now.  Note that we free this memory only for the
3147c478bd9Sstevel@tonic-gate 	     * thread that calls prldap_thread_dispose_handle(), which
3157c478bd9Sstevel@tonic-gate 	     * should be the one that called ldap_unbind() -- see
3167c478bd9Sstevel@tonic-gate 	     * prldap_return_map().  Not freeing the memory used by
3177c478bd9Sstevel@tonic-gate 	     * other threads is deemed acceptable since it will be
3187c478bd9Sstevel@tonic-gate 	     * recycled and used by other LDAP sessions.  All of the
3197c478bd9Sstevel@tonic-gate 	     * thread-private memory is freed when a thread exits
3207c478bd9Sstevel@tonic-gate 	     * (inside the prldap_tsd_destroy() function).
3217c478bd9Sstevel@tonic-gate 	     */
3227c478bd9Sstevel@tonic-gate 	    eip = (PRLDAP_ErrorInfo *)PR_Calloc( 1,
3237c478bd9Sstevel@tonic-gate 		    sizeof( PRLDAP_ErrorInfo ));
3247c478bd9Sstevel@tonic-gate 	    if ( eip == NULL ) {
3257c478bd9Sstevel@tonic-gate 		return;	/* punt */
3267c478bd9Sstevel@tonic-gate 	    }
3277c478bd9Sstevel@tonic-gate 	    (void)prldap_set_thread_private( map->prtm_index, eip );
3287c478bd9Sstevel@tonic-gate 	}
3297c478bd9Sstevel@tonic-gate 
3307c478bd9Sstevel@tonic-gate 	eip->plei_lderrno = err;
3317c478bd9Sstevel@tonic-gate 	if ( eip->plei_matched != NULL ) {
3327c478bd9Sstevel@tonic-gate 	    ldap_memfree( eip->plei_matched );
3337c478bd9Sstevel@tonic-gate 	}
3347c478bd9Sstevel@tonic-gate 	eip->plei_matched = matched;
3357c478bd9Sstevel@tonic-gate 	if ( eip->plei_errmsg != NULL ) {
3367c478bd9Sstevel@tonic-gate 	    ldap_memfree( eip->plei_errmsg );
3377c478bd9Sstevel@tonic-gate 	}
3387c478bd9Sstevel@tonic-gate 	eip->plei_errmsg = errmsg;
3397c478bd9Sstevel@tonic-gate     }
3407c478bd9Sstevel@tonic-gate }
3417c478bd9Sstevel@tonic-gate #endif
3427c478bd9Sstevel@tonic-gate 
3437c478bd9Sstevel@tonic-gate 
3447c478bd9Sstevel@tonic-gate /*
3457c478bd9Sstevel@tonic-gate  * Called when a new LDAP * session handle is allocated.
3467c478bd9Sstevel@tonic-gate  * Allocate thread-private data for error information, but only if
3477c478bd9Sstevel@tonic-gate  * it has not already been allocated and the get_ld_error callback has
3487c478bd9Sstevel@tonic-gate  * been installed.  If ld is not NULL when prldap_install_thread_functions()
3497c478bd9Sstevel@tonic-gate  * is called, we will have already allocated the thread-private data there.
3507c478bd9Sstevel@tonic-gate  */
3517c478bd9Sstevel@tonic-gate int
3527c478bd9Sstevel@tonic-gate prldap_thread_new_handle( LDAP *ld, void *sessionarg )
3537c478bd9Sstevel@tonic-gate {
3547c478bd9Sstevel@tonic-gate     struct ldap_thread_fns	tfns;
3557c478bd9Sstevel@tonic-gate 
3567c478bd9Sstevel@tonic-gate #ifndef _SOLARIS_SDK
3577c478bd9Sstevel@tonic-gate     if ( ldap_get_option( ld, LDAP_OPT_THREAD_FN_PTRS, (void *)&tfns ) != 0 ) {
3587c478bd9Sstevel@tonic-gate 	return( LDAP_LOCAL_ERROR );
3597c478bd9Sstevel@tonic-gate     }
3607c478bd9Sstevel@tonic-gate 
3617c478bd9Sstevel@tonic-gate     if ( tfns.ltf_lderrno_arg == NULL && tfns.ltf_get_lderrno != NULL ) {
3627c478bd9Sstevel@tonic-gate 	if (( tfns.ltf_lderrno_arg = (void *)prldap_allocate_map( ld )) == NULL
3637c478bd9Sstevel@tonic-gate 		|| ldap_set_option( ld, LDAP_OPT_THREAD_FN_PTRS,
3647c478bd9Sstevel@tonic-gate 		(void *)&tfns ) != 0 ) {
3657c478bd9Sstevel@tonic-gate 	    return( LDAP_LOCAL_ERROR );
3667c478bd9Sstevel@tonic-gate 	}
3677c478bd9Sstevel@tonic-gate     }
3687c478bd9Sstevel@tonic-gate #endif
3697c478bd9Sstevel@tonic-gate 
3707c478bd9Sstevel@tonic-gate     return( LDAP_SUCCESS );
3717c478bd9Sstevel@tonic-gate }
3727c478bd9Sstevel@tonic-gate 
3737c478bd9Sstevel@tonic-gate 
3747c478bd9Sstevel@tonic-gate /*
3757c478bd9Sstevel@tonic-gate  * Called when an LDAP * session handle is being destroyed.
3767c478bd9Sstevel@tonic-gate  * Clean up our thread private data map.
3777c478bd9Sstevel@tonic-gate  */
3787c478bd9Sstevel@tonic-gate void
3797c478bd9Sstevel@tonic-gate prldap_thread_dispose_handle( LDAP *ld, void *sessionarg )
3807c478bd9Sstevel@tonic-gate {
3817c478bd9Sstevel@tonic-gate #ifndef _SOLARIS_SDK
3827c478bd9Sstevel@tonic-gate     struct ldap_thread_fns	tfns;
3837c478bd9Sstevel@tonic-gate 
3847c478bd9Sstevel@tonic-gate     if ( ldap_get_option( ld, LDAP_OPT_THREAD_FN_PTRS,
3857c478bd9Sstevel@tonic-gate 	    (void *)&tfns ) == 0 &&
3867c478bd9Sstevel@tonic-gate 	    tfns.ltf_lderrno_arg != NULL ) {
3877c478bd9Sstevel@tonic-gate 	prldap_return_map( (PRLDAP_TPDMap *)tfns.ltf_lderrno_arg );
3887c478bd9Sstevel@tonic-gate     }
3897c478bd9Sstevel@tonic-gate #endif
3907c478bd9Sstevel@tonic-gate }
3917c478bd9Sstevel@tonic-gate 
3927c478bd9Sstevel@tonic-gate 
3937c478bd9Sstevel@tonic-gate #ifndef _SOLARIS_SDK
3947c478bd9Sstevel@tonic-gate static PRStatus
3957c478bd9Sstevel@tonic-gate prldap_init_tpd( void )
3967c478bd9Sstevel@tonic-gate {
3977c478bd9Sstevel@tonic-gate     if (( prldap_map_mutex = PR_NewLock()) == NULL || PR_NewThreadPrivateIndex(
3987c478bd9Sstevel@tonic-gate 		&prldap_tpdindex, prldap_tsd_destroy ) != PR_SUCCESS ) {
3997c478bd9Sstevel@tonic-gate 	return( PR_FAILURE );
4007c478bd9Sstevel@tonic-gate     }
4017c478bd9Sstevel@tonic-gate 
4027c478bd9Sstevel@tonic-gate     prldap_map_list = NULL;
4037c478bd9Sstevel@tonic-gate 
4047c478bd9Sstevel@tonic-gate     return( PR_SUCCESS );
4057c478bd9Sstevel@tonic-gate }
4067c478bd9Sstevel@tonic-gate 
4077c478bd9Sstevel@tonic-gate 
4087c478bd9Sstevel@tonic-gate /*
4097c478bd9Sstevel@tonic-gate  * Function: prldap_allocate_map()
4107c478bd9Sstevel@tonic-gate  * Description: allocate a thread-private data map to use for a new
4117c478bd9Sstevel@tonic-gate  *	LDAP session handle.
4127c478bd9Sstevel@tonic-gate  * Returns: a pointer to the TPD map or NULL if none available.
4137c478bd9Sstevel@tonic-gate  */
4147c478bd9Sstevel@tonic-gate static PRLDAP_TPDMap *
4157c478bd9Sstevel@tonic-gate prldap_allocate_map( LDAP *ld )
4167c478bd9Sstevel@tonic-gate {
4177c478bd9Sstevel@tonic-gate     PRLDAP_TPDMap	*map, *prevmap;
4187c478bd9Sstevel@tonic-gate 
4197c478bd9Sstevel@tonic-gate     PR_Lock( prldap_map_mutex );
4207c478bd9Sstevel@tonic-gate 
4217c478bd9Sstevel@tonic-gate     /*
4227c478bd9Sstevel@tonic-gate      * first look for a map that is already allocated but free to be re-used
4237c478bd9Sstevel@tonic-gate      */
4247c478bd9Sstevel@tonic-gate     prevmap = NULL;
4257c478bd9Sstevel@tonic-gate     for ( map = prldap_map_list; map != NULL; map = map->prtm_next ) {
4267c478bd9Sstevel@tonic-gate 	if ( map->prtm_ld == NULL ) {
4277c478bd9Sstevel@tonic-gate 	    break;
4287c478bd9Sstevel@tonic-gate 	}
4297c478bd9Sstevel@tonic-gate 	prevmap = map;
4307c478bd9Sstevel@tonic-gate     }
4317c478bd9Sstevel@tonic-gate 
4327c478bd9Sstevel@tonic-gate     /*
4337c478bd9Sstevel@tonic-gate      * if none we found (map == NULL), try to allocate a new one and add it
4347c478bd9Sstevel@tonic-gate      * to the end of our global list.
4357c478bd9Sstevel@tonic-gate      */
4367c478bd9Sstevel@tonic-gate     if ( map == NULL ) {
4377c478bd9Sstevel@tonic-gate 	PRUintn	tpdindex;
4387c478bd9Sstevel@tonic-gate 
4397c478bd9Sstevel@tonic-gate 	tpdindex = prldap_new_tpdindex();
4407c478bd9Sstevel@tonic-gate 	map = (PRLDAP_TPDMap *)PR_Malloc( sizeof( PRLDAP_TPDMap ));
4417c478bd9Sstevel@tonic-gate 	if ( map != NULL ) {
4427c478bd9Sstevel@tonic-gate 	    map->prtm_index = tpdindex;
4437c478bd9Sstevel@tonic-gate 	    map->prtm_next = NULL;
4447c478bd9Sstevel@tonic-gate 	    if ( prevmap == NULL ) {
4457c478bd9Sstevel@tonic-gate 		prldap_map_list = map;
4467c478bd9Sstevel@tonic-gate 	    } else {
4477c478bd9Sstevel@tonic-gate 		prevmap->prtm_next = map;
4487c478bd9Sstevel@tonic-gate 	    }
4497c478bd9Sstevel@tonic-gate 	}
4507c478bd9Sstevel@tonic-gate     }
4517c478bd9Sstevel@tonic-gate 
4527c478bd9Sstevel@tonic-gate     if ( map != NULL ) {
4537c478bd9Sstevel@tonic-gate 	map->prtm_ld = ld;	/* now marked as "in use" */
4547c478bd9Sstevel@tonic-gate 				/* since we are reusing...reset */
4557c478bd9Sstevel@tonic-gate 				/* to initial state */
4567c478bd9Sstevel@tonic-gate 	(void)prldap_set_thread_private( map->prtm_index, NULL );
4577c478bd9Sstevel@tonic-gate     }
4587c478bd9Sstevel@tonic-gate 
4597c478bd9Sstevel@tonic-gate     PR_Unlock( prldap_map_mutex );
4607c478bd9Sstevel@tonic-gate 
4617c478bd9Sstevel@tonic-gate     return( map );
4627c478bd9Sstevel@tonic-gate }
4637c478bd9Sstevel@tonic-gate 
4647c478bd9Sstevel@tonic-gate 
4657c478bd9Sstevel@tonic-gate /*
4667c478bd9Sstevel@tonic-gate  * Function: prldap_return_map()
4677c478bd9Sstevel@tonic-gate  * Description: return a thread-private data map to the pool of ones
4687c478bd9Sstevel@tonic-gate  *	available for re-use.
4697c478bd9Sstevel@tonic-gate  */
4707c478bd9Sstevel@tonic-gate static void
4717c478bd9Sstevel@tonic-gate prldap_return_map( PRLDAP_TPDMap *map )
4727c478bd9Sstevel@tonic-gate {
4737c478bd9Sstevel@tonic-gate     PRLDAP_ErrorInfo	*eip;
4747c478bd9Sstevel@tonic-gate 
4757c478bd9Sstevel@tonic-gate     PR_Lock( prldap_map_mutex );
4767c478bd9Sstevel@tonic-gate 
4777c478bd9Sstevel@tonic-gate     /*
4787c478bd9Sstevel@tonic-gate      * Dispose of thread-private LDAP error information.  Note that this
4797c478bd9Sstevel@tonic-gate      * only disposes of the memory consumed on THIS thread, but that is
4807c478bd9Sstevel@tonic-gate      * okay.  See the comment in prldap_set_ld_error() for the reason why.
4817c478bd9Sstevel@tonic-gate      */
4827c478bd9Sstevel@tonic-gate     if (( eip = (PRLDAP_ErrorInfo *)prldap_get_thread_private(
4837c478bd9Sstevel@tonic-gate 		map->prtm_index )) != NULL &&
4847c478bd9Sstevel@tonic-gate 		prldap_set_thread_private( map->prtm_index, NULL ) == 0 ) {
4857c478bd9Sstevel@tonic-gate 	if ( eip->plei_matched != NULL ) {
4867c478bd9Sstevel@tonic-gate 	    ldap_memfree( eip->plei_matched );
4877c478bd9Sstevel@tonic-gate 	}
4887c478bd9Sstevel@tonic-gate 	if ( eip->plei_errmsg != NULL ) {
4897c478bd9Sstevel@tonic-gate 	    ldap_memfree( eip->plei_errmsg );
4907c478bd9Sstevel@tonic-gate 	}
4917c478bd9Sstevel@tonic-gate 
4927c478bd9Sstevel@tonic-gate 	PR_Free( eip );
4937c478bd9Sstevel@tonic-gate     }
4947c478bd9Sstevel@tonic-gate 
4957c478bd9Sstevel@tonic-gate     /* mark map as available for re-use */
4967c478bd9Sstevel@tonic-gate     map->prtm_ld = NULL;
4977c478bd9Sstevel@tonic-gate 
4987c478bd9Sstevel@tonic-gate     PR_Unlock( prldap_map_mutex );
4997c478bd9Sstevel@tonic-gate }
5007c478bd9Sstevel@tonic-gate 
5017c478bd9Sstevel@tonic-gate 
5027c478bd9Sstevel@tonic-gate /*
5037c478bd9Sstevel@tonic-gate  * Function: prldap_new_tpdindex()
5047c478bd9Sstevel@tonic-gate  * Description: allocate a thread-private data index.
5057c478bd9Sstevel@tonic-gate  * Returns: the new index.
5067c478bd9Sstevel@tonic-gate  */
5077c478bd9Sstevel@tonic-gate static PRUintn
5087c478bd9Sstevel@tonic-gate prldap_new_tpdindex( void )
5097c478bd9Sstevel@tonic-gate {
5107c478bd9Sstevel@tonic-gate     PRUintn	tpdindex;
5117c478bd9Sstevel@tonic-gate 
5127c478bd9Sstevel@tonic-gate     tpdindex = (PRUintn)PR_AtomicIncrement( &prldap_tpd_maxindex );
5137c478bd9Sstevel@tonic-gate     return( tpdindex );
5147c478bd9Sstevel@tonic-gate }
5157c478bd9Sstevel@tonic-gate 
5167c478bd9Sstevel@tonic-gate 
5177c478bd9Sstevel@tonic-gate /*
5187c478bd9Sstevel@tonic-gate  * Function: prldap_set_thread_private()
5197c478bd9Sstevel@tonic-gate  * Description: store a piece of thread-private data.
5207c478bd9Sstevel@tonic-gate  * Returns: 0 if successful and -1 if not.
5217c478bd9Sstevel@tonic-gate  */
5227c478bd9Sstevel@tonic-gate static int
5237c478bd9Sstevel@tonic-gate prldap_set_thread_private( PRInt32 tpdindex, void *priv )
5247c478bd9Sstevel@tonic-gate {
5257c478bd9Sstevel@tonic-gate     PRLDAP_TPDHeader	*tsdhdr;
5267c478bd9Sstevel@tonic-gate 
5277c478bd9Sstevel@tonic-gate     if ( tpdindex > prldap_tpd_maxindex ) {
5287c478bd9Sstevel@tonic-gate 	return( -1 );	/* bad index */
5297c478bd9Sstevel@tonic-gate     }
5307c478bd9Sstevel@tonic-gate 
5317c478bd9Sstevel@tonic-gate     tsdhdr = (PRLDAP_TPDHeader *)PR_GetThreadPrivate( prldap_tpdindex );
5327c478bd9Sstevel@tonic-gate     if ( tsdhdr == NULL || tpdindex >= tsdhdr->ptpdh_tpd_count ) {
5337c478bd9Sstevel@tonic-gate 	tsdhdr = prldap_tsd_realloc( tsdhdr, tpdindex );
5347c478bd9Sstevel@tonic-gate 	if ( tsdhdr == NULL ) {
5357c478bd9Sstevel@tonic-gate 	    return( -1 );	/* realloc failed */
5367c478bd9Sstevel@tonic-gate 	}
5377c478bd9Sstevel@tonic-gate     }
5387c478bd9Sstevel@tonic-gate 
5397c478bd9Sstevel@tonic-gate     tsdhdr->ptpdh_dataitems[ tpdindex ] = priv;
5407c478bd9Sstevel@tonic-gate     return( 0 );
5417c478bd9Sstevel@tonic-gate }
5427c478bd9Sstevel@tonic-gate 
5437c478bd9Sstevel@tonic-gate 
5447c478bd9Sstevel@tonic-gate /*
5457c478bd9Sstevel@tonic-gate  * Function: prldap_get_thread_private()
5467c478bd9Sstevel@tonic-gate  * Description: retrieve a piece of thread-private data.  If not set,
5477c478bd9Sstevel@tonic-gate  *	NULL is returned.
5487c478bd9Sstevel@tonic-gate  * Returns: 0 if successful and -1 if not.
5497c478bd9Sstevel@tonic-gate  */
5507c478bd9Sstevel@tonic-gate static void *
5517c478bd9Sstevel@tonic-gate prldap_get_thread_private( PRInt32 tpdindex )
5527c478bd9Sstevel@tonic-gate {
5537c478bd9Sstevel@tonic-gate     PRLDAP_TPDHeader	*tsdhdr;
5547c478bd9Sstevel@tonic-gate 
5557c478bd9Sstevel@tonic-gate     tsdhdr = (PRLDAP_TPDHeader *)PR_GetThreadPrivate( prldap_tpdindex );
5567c478bd9Sstevel@tonic-gate     if ( tsdhdr == NULL ) {
5577c478bd9Sstevel@tonic-gate 	return( NULL );	/* no thread private data */
5587c478bd9Sstevel@tonic-gate     }
5597c478bd9Sstevel@tonic-gate 
5607c478bd9Sstevel@tonic-gate     if ( tpdindex >= tsdhdr->ptpdh_tpd_count
5617c478bd9Sstevel@tonic-gate 		|| tsdhdr->ptpdh_dataitems == NULL ) {
5627c478bd9Sstevel@tonic-gate 	return( NULL );	/* fewer data items than requested index */
5637c478bd9Sstevel@tonic-gate     }
5647c478bd9Sstevel@tonic-gate 
5657c478bd9Sstevel@tonic-gate     return( tsdhdr->ptpdh_dataitems[ tpdindex ] );
5667c478bd9Sstevel@tonic-gate }
5677c478bd9Sstevel@tonic-gate 
5687c478bd9Sstevel@tonic-gate 
5697c478bd9Sstevel@tonic-gate /*
5707c478bd9Sstevel@tonic-gate  * Function: prldap_tsd_realloc()
5717c478bd9Sstevel@tonic-gate  * Description: enlarge the thread-private data array.
5727c478bd9Sstevel@tonic-gate  * Returns: the new PRLDAP_TPDHeader value (non-NULL if successful).
5737c478bd9Sstevel@tonic-gate  * Note: tsdhdr can be NULL (allocates a new PRLDAP_TPDHeader).
5747c478bd9Sstevel@tonic-gate  */
5757c478bd9Sstevel@tonic-gate static PRLDAP_TPDHeader *
5767c478bd9Sstevel@tonic-gate prldap_tsd_realloc( PRLDAP_TPDHeader *tsdhdr, int maxindex )
5777c478bd9Sstevel@tonic-gate {
5787c478bd9Sstevel@tonic-gate     void	*newdataitems = NULL;
5797c478bd9Sstevel@tonic-gate     int		count;
5807c478bd9Sstevel@tonic-gate 
5817c478bd9Sstevel@tonic-gate     if ( tsdhdr == NULL ) {
5827c478bd9Sstevel@tonic-gate 	/* allocate a new thread private data header */
5837c478bd9Sstevel@tonic-gate 	if (( tsdhdr = PR_Calloc( 1, sizeof( PRLDAP_TPDHeader ))) == NULL ) {
5847c478bd9Sstevel@tonic-gate 	    return( NULL );
5857c478bd9Sstevel@tonic-gate 	}
5867c478bd9Sstevel@tonic-gate 	(void)PR_SetThreadPrivate( prldap_tpdindex, tsdhdr );
5877c478bd9Sstevel@tonic-gate     }
5887c478bd9Sstevel@tonic-gate 
5897c478bd9Sstevel@tonic-gate     /*
5907c478bd9Sstevel@tonic-gate      * Make the size of the new array the next highest multiple of
5917c478bd9Sstevel@tonic-gate      * the array increment value that is greater than maxindex.
5927c478bd9Sstevel@tonic-gate      */
5937c478bd9Sstevel@tonic-gate     count = PRLDAP_TPD_ARRAY_INCREMENT *
5947c478bd9Sstevel@tonic-gate 		( 1 + ( maxindex / PRLDAP_TPD_ARRAY_INCREMENT ));
5957c478bd9Sstevel@tonic-gate 
5967c478bd9Sstevel@tonic-gate     /* increase the size of the data item array if necessary */
5977c478bd9Sstevel@tonic-gate     if ( count > tsdhdr->ptpdh_tpd_count  ) {
5987c478bd9Sstevel@tonic-gate 	newdataitems = (PRLDAP_ErrorInfo *)PR_Calloc( count, sizeof( void * ));
5997c478bd9Sstevel@tonic-gate 	if ( newdataitems == NULL ) {
6007c478bd9Sstevel@tonic-gate 	    return( NULL );
6017c478bd9Sstevel@tonic-gate 	}
6027c478bd9Sstevel@tonic-gate 	if ( tsdhdr->ptpdh_dataitems != NULL ) {	/* preserve old data */
6037c478bd9Sstevel@tonic-gate 	    memcpy( newdataitems, tsdhdr->ptpdh_dataitems,
6047c478bd9Sstevel@tonic-gate 			tsdhdr->ptpdh_tpd_count * sizeof( void * ));
6057c478bd9Sstevel@tonic-gate 	    PR_Free( tsdhdr->ptpdh_dataitems );
6067c478bd9Sstevel@tonic-gate 	}
6077c478bd9Sstevel@tonic-gate 
6087c478bd9Sstevel@tonic-gate 	tsdhdr->ptpdh_tpd_count = count;
6097c478bd9Sstevel@tonic-gate 	tsdhdr->ptpdh_dataitems = newdataitems;
6107c478bd9Sstevel@tonic-gate     }
6117c478bd9Sstevel@tonic-gate 
6127c478bd9Sstevel@tonic-gate     return( tsdhdr );
6137c478bd9Sstevel@tonic-gate }
6147c478bd9Sstevel@tonic-gate 
6157c478bd9Sstevel@tonic-gate 
6167c478bd9Sstevel@tonic-gate /*
6177c478bd9Sstevel@tonic-gate  * Function: prldap_tsd_destroy()
6187c478bd9Sstevel@tonic-gate  * Description: Free a thread-private data array. Installed as an NSPR TPD
6197c478bd9Sstevel@tonic-gate  *	destructor function
6207c478bd9Sstevel@tonic-gate  * Returns: nothing.
6217c478bd9Sstevel@tonic-gate  * Note: this function assumes that each TPD item installed at the PRLDAP
6227c478bd9Sstevel@tonic-gate  *	level can be freed with a call to PR_Free().
6237c478bd9Sstevel@tonic-gate  */
6247c478bd9Sstevel@tonic-gate static void
6257c478bd9Sstevel@tonic-gate prldap_tsd_destroy( void *priv )
6267c478bd9Sstevel@tonic-gate {
6277c478bd9Sstevel@tonic-gate     PRLDAP_TPDHeader	*tsdhdr;
6287c478bd9Sstevel@tonic-gate     int			i;
6297c478bd9Sstevel@tonic-gate 
6307c478bd9Sstevel@tonic-gate     tsdhdr = (PRLDAP_TPDHeader *)priv;
6317c478bd9Sstevel@tonic-gate     if ( tsdhdr != NULL ) {
6327c478bd9Sstevel@tonic-gate 	if ( tsdhdr->ptpdh_dataitems != NULL ) {
6337c478bd9Sstevel@tonic-gate 	    for ( i = 0; i < tsdhdr->ptpdh_tpd_count; ++i ) {
6347c478bd9Sstevel@tonic-gate 		if ( tsdhdr->ptpdh_dataitems[ i ] != NULL ) {
6357c478bd9Sstevel@tonic-gate 		    PR_Free( tsdhdr->ptpdh_dataitems[ i ] );
6367c478bd9Sstevel@tonic-gate 		    tsdhdr->ptpdh_dataitems[ i ] = NULL;
6377c478bd9Sstevel@tonic-gate 		}
6387c478bd9Sstevel@tonic-gate 	    }
6397c478bd9Sstevel@tonic-gate 	    PR_Free( tsdhdr->ptpdh_dataitems );
6407c478bd9Sstevel@tonic-gate 	    tsdhdr->ptpdh_dataitems = NULL;
6417c478bd9Sstevel@tonic-gate 	}
6427c478bd9Sstevel@tonic-gate 	PR_Free( tsdhdr );
6437c478bd9Sstevel@tonic-gate     }
6447c478bd9Sstevel@tonic-gate }
6457c478bd9Sstevel@tonic-gate #endif
6467c478bd9Sstevel@tonic-gate 
6477c478bd9Sstevel@tonic-gate #ifdef	_SOLARIS_SDK
6487c478bd9Sstevel@tonic-gate #pragma	init(prldap_nspr_init)
6497c478bd9Sstevel@tonic-gate static mutex_t	nspr_init_lock = DEFAULTMUTEX;
6507c478bd9Sstevel@tonic-gate static mutex_t	nspr_idle_lock = DEFAULTMUTEX;
6517c478bd9Sstevel@tonic-gate static cond_t	nspr_idle_cond = DEFAULTCV;
6527c478bd9Sstevel@tonic-gate static int	nspr_pr_init_is_done = 0;
6537c478bd9Sstevel@tonic-gate static int	nspr_initialized = 0;
6547c478bd9Sstevel@tonic-gate 
6557c478bd9Sstevel@tonic-gate void *
6567c478bd9Sstevel@tonic-gate prldap_nspr_idle_primordial_thread(void *arg) {
6577c478bd9Sstevel@tonic-gate 	/*
6587c478bd9Sstevel@tonic-gate 	 * Make sure PR_Init finishes before any other thread can continue
6597c478bd9Sstevel@tonic-gate 	 */
6607c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&nspr_idle_lock);
661*d4204c85Sraf 	if (PR_Initialized() == PR_FALSE) {
662*d4204c85Sraf 		/*
663*d4204c85Sraf 		 * PR_Init() changes the current thread's
664*d4204c85Sraf 		 * priority.  Save and restore the priority.
665*d4204c85Sraf 		 */
666*d4204c85Sraf 		int priority;
667*d4204c85Sraf 		(void) thr_getprio(thr_self(), &priority);
6687c478bd9Sstevel@tonic-gate 		PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
669*d4204c85Sraf 		(void) thr_setprio(thr_self(), priority);
670*d4204c85Sraf 	}
6717c478bd9Sstevel@tonic-gate 	nspr_pr_init_is_done = 1;
6727c478bd9Sstevel@tonic-gate 	(void) cond_signal(&nspr_idle_cond);
6737c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&nspr_idle_lock);
6747c478bd9Sstevel@tonic-gate 
6757c478bd9Sstevel@tonic-gate 	/* Debug only */
6767c478bd9Sstevel@tonic-gate 	syslog(LOG_DEBUG, "NSPR is initialized by the"
6777c478bd9Sstevel@tonic-gate 		"idle primordial thread tid %ld created by thread "
6787c478bd9Sstevel@tonic-gate 		"tid %ld", thr_self(), (long)arg);
6797c478bd9Sstevel@tonic-gate 	pause();
6807c478bd9Sstevel@tonic-gate 
6817c478bd9Sstevel@tonic-gate }
6827c478bd9Sstevel@tonic-gate 
6837c478bd9Sstevel@tonic-gate /*
6847c478bd9Sstevel@tonic-gate  * Initialize NSPR once
6857c478bd9Sstevel@tonic-gate  *
6867c478bd9Sstevel@tonic-gate  * Ideally this should be done in .init of NSPR.
6877c478bd9Sstevel@tonic-gate  * This is a workaround so only main thread can initialize
6887c478bd9Sstevel@tonic-gate  * NSPR but main() does not need to call PR_Init().
6897c478bd9Sstevel@tonic-gate  * The future direction is NSPR free so we don't want programs
6907c478bd9Sstevel@tonic-gate  * to call PR_Init().
6917c478bd9Sstevel@tonic-gate  *
6927c478bd9Sstevel@tonic-gate  * For most of cases, programs link libldap (-lldap)
6937c478bd9Sstevel@tonic-gate  * and .init is executed before the control is transfered to
6947c478bd9Sstevel@tonic-gate  * main().
6957c478bd9Sstevel@tonic-gate  * But for programs linking libnsl (-lnsl), libldap is loaded
6967c478bd9Sstevel@tonic-gate  * via dlopen("nss_ldap.so.1", RTLD_LAZY) so the thread loads
6977c478bd9Sstevel@tonic-gate  * libldap is not necessary a main or a primordial
6987c478bd9Sstevel@tonic-gate  * thread. In the latter case, an idle primordial thread is created
6997c478bd9Sstevel@tonic-gate  * to initialize NSPR so NSPR won't be initialized by non-primordial
7007c478bd9Sstevel@tonic-gate  * threads.
7017c478bd9Sstevel@tonic-gate  * libldap is built with "-z nodelete" so libldap and libnspr4.so
7027c478bd9Sstevel@tonic-gate  * are persistent in the address space.
7037c478bd9Sstevel@tonic-gate  */
7047c478bd9Sstevel@tonic-gate void
7057c478bd9Sstevel@tonic-gate prldap_nspr_init(void) {
7067c478bd9Sstevel@tonic-gate 	struct sigaction	action;
7077c478bd9Sstevel@tonic-gate 
7087c478bd9Sstevel@tonic-gate 	/*
7097c478bd9Sstevel@tonic-gate 	 * For performance reason, test it here first
7107c478bd9Sstevel@tonic-gate 	 */
7117c478bd9Sstevel@tonic-gate 	if (nspr_initialized != 0)
7127c478bd9Sstevel@tonic-gate 		return;
7137c478bd9Sstevel@tonic-gate 
7147c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&nspr_init_lock);
7157c478bd9Sstevel@tonic-gate 	/* Make sure PR_Init() is executed only once */
7167c478bd9Sstevel@tonic-gate 	if (nspr_initialized == 0) {
7177c478bd9Sstevel@tonic-gate 		/*
7187c478bd9Sstevel@tonic-gate 		 * PR_Init changes the signal handler of SIGPIPE to SIG_IGN.
7197c478bd9Sstevel@tonic-gate 		 * Save the original and restore it after PR_Init.
7207c478bd9Sstevel@tonic-gate 		 */
7217c478bd9Sstevel@tonic-gate 		(void) sigaction(SIGPIPE, NULL, &action);
7227c478bd9Sstevel@tonic-gate 
7237c478bd9Sstevel@tonic-gate 		if (thr_self() == 1) {
7247c478bd9Sstevel@tonic-gate 			/* main thread */
725*d4204c85Sraf 			if (PR_Initialized() == PR_FALSE) {
726*d4204c85Sraf 				/*
727*d4204c85Sraf 				 * PR_Init() changes the current thread's
728*d4204c85Sraf 				 * priority.  Save and restore the priority.
729*d4204c85Sraf 				 */
730*d4204c85Sraf 				int priority;
731*d4204c85Sraf 				(void) thr_getprio(thr_self(), &priority);
732*d4204c85Sraf 				PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
733*d4204c85Sraf 				(void) thr_setprio(thr_self(), priority);
734*d4204c85Sraf 			}
7357c478bd9Sstevel@tonic-gate 			nspr_initialized = 1;
7367c478bd9Sstevel@tonic-gate 		} else {
7377c478bd9Sstevel@tonic-gate 			if (thr_create(NULL, NULL,
7387c478bd9Sstevel@tonic-gate 				prldap_nspr_idle_primordial_thread,
7397c478bd9Sstevel@tonic-gate 				(void *)thr_self(), THR_DETACHED, NULL) != 0) {
7407c478bd9Sstevel@tonic-gate 					syslog(LOG_ERR,
7417c478bd9Sstevel@tonic-gate 					"libldap:.init: Can't create thread. "
7427c478bd9Sstevel@tonic-gate 					"%s", strerror(errno));
7437c478bd9Sstevel@tonic-gate 			} else {
7447c478bd9Sstevel@tonic-gate 			/*
7457c478bd9Sstevel@tonic-gate 			 * Make sure PR_Init finishes before any other thread
7467c478bd9Sstevel@tonic-gate 			 * can continue.
7477c478bd9Sstevel@tonic-gate 			 * It's unlikely, but not impossible that this thread
7487c478bd9Sstevel@tonic-gate 			 * finishes dlopen and  starts to call
7497c478bd9Sstevel@tonic-gate 			 * LDAP API when the idle thread still has not
7507c478bd9Sstevel@tonic-gate 			 * finished PR_Init() yet.
7517c478bd9Sstevel@tonic-gate 			 */
7527c478bd9Sstevel@tonic-gate 				(void) mutex_lock(&nspr_idle_lock);
7537c478bd9Sstevel@tonic-gate 				while (nspr_pr_init_is_done == 0) {
7547c478bd9Sstevel@tonic-gate 					(void) cond_wait(&nspr_idle_cond,
7557c478bd9Sstevel@tonic-gate 							&nspr_idle_lock);
7567c478bd9Sstevel@tonic-gate 
7577c478bd9Sstevel@tonic-gate 				}
7587c478bd9Sstevel@tonic-gate 				(void) mutex_unlock(&nspr_idle_lock);
7597c478bd9Sstevel@tonic-gate 				nspr_initialized = 1;
7607c478bd9Sstevel@tonic-gate 			}
7617c478bd9Sstevel@tonic-gate 		}
7627c478bd9Sstevel@tonic-gate 		/*
7637c478bd9Sstevel@tonic-gate 		 * Restore signal handling attributes of SIGPIPE
7647c478bd9Sstevel@tonic-gate 		 */
7657c478bd9Sstevel@tonic-gate 		(void) sigaction(SIGPIPE, &action, NULL);
7667c478bd9Sstevel@tonic-gate 
7677c478bd9Sstevel@tonic-gate 	}
7687c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&nspr_init_lock);
7697c478bd9Sstevel@tonic-gate }
7707c478bd9Sstevel@tonic-gate #endif
771