1 /* thr_debug.c - wrapper around the chosen thread wrapper, for debugging. */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 2005-2021 The OpenLDAP Foundation.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted only as authorized by the OpenLDAP
10  * Public License.
11  *
12  * A copy of this license is available in file LICENSE in the
13  * top-level directory of the distribution or, alternatively, at
14  * <http://www.OpenLDAP.org/license.html>.
15  */
16 
17 /*
18  * This package provides several types of thread operation debugging:
19  *
20  * - Check the results of operations on threads, mutexes, condition
21  *   variables and read/write locks.  Also check some thread pool
22  *   operations, but not those for which failure can happen in normal
23  *   slapd operation.
24  *
25  * - Wrap those types except threads and pools in structs with state
26  *   information, and check that on all operations:
27  *
28  *   + Check that the resources are initialized and are only used at
29  *     their original address (i.e. not realloced or copied).
30  *
31  *   + Check the owner (thread ID) on mutex operations.
32  *
33  *   + Optionally allocate a reference to a byte of dummy memory.
34  *     This lets malloc debuggers see some incorrect use as memory
35  *     leaks, access to freed memory, etc.
36  *
37  * - Print an error message and by default abort() upon errors.
38  *
39  * - Print a count of leaked thread resources after cleanup.
40  *
41  * Compile-time (./configure) setup:  Macros defined in CPPFLAGS.
42  *
43  *   LDAP_THREAD_DEBUG or LDAP_THREAD_DEBUG=2
44  *      Enables debugging, but value & 2 turns off type wrapping.
45  *
46  *   LDAP_UINTPTR_T=integer type to hold pointers, preferably unsigned.
47  *      Used by dummy memory option "scramble". Default = unsigned long.
48  *
49  *   LDAP_DEBUG_THREAD_NONE = initializer for a "no thread" thread ID.
50  *
51  *   In addition, you may need to set up an implementation-specific way
52  *      to enable whatever error checking your thread library provides.
53  *      Currently only implemented for Posix threads (pthreads), where
54  *      you may need to define LDAP_INT_THREAD_MUTEXATTR.  The default
55  *      is PTHREAD_MUTEX_ERRORCHECK, or PTHREAD_MUTEX_ERRORCHECK_NP for
56  *      Linux threads.  See pthread_mutexattr_settype(3).
57  *
58  * Run-time configuration:
59  *
60  *  Memory debugging tools:
61  *   Tools that report uninitialized memory accesses should disable
62  *   such warnings about the function debug_already_initialized().
63  *   Alternatively, include "noreinit" (below) in $LDAP_THREAD_DEBUG.
64  *
65  *  Environment variable $LDAP_THREAD_DEBUG:
66  *   The variable may contain a comma- or space-separated option list.
67  *   Options:
68  *      off      - Disable this package.  (It still slows things down).
69  *      tracethreads - Report create/join/exit/kill of threads.
70  *      noabort  - Do not abort() on errors.
71  *      noerror  - Do not report errors.  Implies noabort.
72  *      nocount  - Do not report counts of unreleased resources.
73  *      nosync   - Disable tests that use synchronization and thus
74  *                 clearly affect thread scheduling:
75  *                 Implies nocount, and cancels threadID if that is set.
76  *                 Note that if you turn on tracethreads or malloc
77  *                 debugging, these also use library calls which may
78  *                 affect thread scheduling (fprintf and malloc).
79  *   The following options do not apply if type wrapping is disabled:
80  *      nomem    - Do not check memory operations.
81  *                 Implies noreinit,noalloc.
82  *      noreinit - Do not catch reinitialization of existing resources.
83  *                 (That test accesses uninitialized memory).
84  *      threadID - Trace thread IDs.  Currently mostly useless.
85  *     Malloc debugging -- allocate dummy memory for initialized
86  *     resources, so malloc debuggers will report them as memory leaks:
87  *      noalloc  - Default.  Do not allocate dummy memory.
88  *      alloc    - Store a pointer to dummy memory.   However, leak
89  *                 detectors might not catch unreleased resources in
90  *                 global variables.
91  *      scramble - Store bitwise complement of dummy memory pointer.
92  *                 That never escapes memory leak detectors -
93  *                 but detection while the program is running will
94  *                 report active resources as leaks.  Do not
95  *                 use this if a garbage collector is in use:-)
96  *      adjptr   - Point to end of dummy memory.
97  *                 Purify reports these as "potential leaks" (PLK).
98  *                 I have not checked other malloc debuggers.
99  */
100 
101 #include "portable.h"
102 
103 #if defined( LDAP_THREAD_DEBUG )
104 
105 #include <stdio.h>
106 #include <ac/errno.h>
107 #include <ac/stdlib.h>
108 #include <ac/string.h>
109 
110 #include "ldap_pvt_thread.h" /* Get the thread interface */
111 #define LDAP_THREAD_IMPLEMENTATION
112 #define LDAP_THREAD_DEBUG_IMPLEMENTATION
113 #define LDAP_THREAD_RDWR_IMPLEMENTATION
114 #define LDAP_THREAD_POOL_IMPLEMENTATION
115 #include "ldap_thr_debug.h"  /* Get the underlying implementation */
116 
117 #ifndef LDAP_THREAD_DEBUG_WRAP
118 #undef	LDAP_THREAD_DEBUG_THREAD_ID
119 #elif !defined LDAP_THREAD_DEBUG_THREAD_ID
120 #define	LDAP_THREAD_DEBUG_THREAD_ID 1
121 #endif
122 
123 /* Use native malloc - the OpenLDAP wrappers may defeat malloc debuggers */
124 #undef malloc
125 #undef calloc
126 #undef realloc
127 #undef free
128 
129 
130 /* Options from environment variable $LDAP_THREAD_DEBUG */
131 enum { Count_no = 0, Count_yes, Count_reported, Count_reported_more };
132 static int count = Count_yes;
133 #ifdef LDAP_THREAD_DEBUG_WRAP
134 enum { Wrap_noalloc, Wrap_alloc, Wrap_scramble, Wrap_adjptr };
135 static int wraptype = Wrap_noalloc, wrap_offset, unwrap_offset;
136 static int nomem, noreinit;
137 #endif
138 #if LDAP_THREAD_DEBUG_THREAD_ID +0
139 static int threadID;
140 #else
141 enum { threadID = 0 };
142 #endif
143 static int nodebug, noabort, noerror, nosync, tracethreads;
144 static int wrap_threads;
145 static int options_done;
146 
147 
148 /* ldap_pvt_thread_initialize() called, ldap_pvt_thread_destroy() not called */
149 static int threading_enabled;
150 
151 
152 /* Resource counts */
153 enum {
154 	Idx_unexited_thread, Idx_unjoined_thread, Idx_locked_mutex,
155 	Idx_mutex, Idx_cond, Idx_rdwr, Idx_tpool, Idx_max
156 };
157 static int resource_counts[Idx_max];
158 static const char *const resource_names[] = {
159 	"unexited threads", "unjoined threads", "locked mutexes",
160 	"mutexes", "conds", "rdwrs", "thread pools"
161 };
162 static ldap_int_thread_mutex_t resource_mutexes[Idx_max];
163 
164 
165 /* Hide pointers from malloc debuggers. */
166 #define SCRAMBLE(ptr) (~(LDAP_UINTPTR_T) (ptr))
167 #define UNSCRAMBLE_usagep(num) ((ldap_debug_usage_info_t *) ~(num))
168 #define UNSCRAMBLE_dummyp(num) ((unsigned char *) ~(num))
169 
170 
171 #define WARN(var, msg)   (warn (__FILE__, __LINE__, (msg), #var, (var)))
172 #define WARN_IF(rc, msg) {if (rc) warn (__FILE__, __LINE__, (msg), #rc, (rc));}
173 
174 #define ERROR(var, msg) { \
175 	if (!noerror) { \
176 		errmsg(__FILE__, __LINE__, (msg), #var, (var)); \
177 		if( !noabort ) abort(); \
178 	} \
179 }
180 
181 #define ERROR_IF(rc, msg) { \
182 	if (!noerror) { \
183 		int rc_ = (rc); \
184 		if (rc_) { \
185 			errmsg(__FILE__, __LINE__, (msg), #rc, rc_); \
186 			if( !noabort ) abort(); \
187 		} \
188 	} \
189 }
190 
191 #ifdef LDAP_THREAD_DEBUG_WRAP
192 #define MEMERROR_IF(rc, msg, mem_act) { \
193 	if (!noerror) { \
194 		int rc_ = (rc); \
195 		if (rc_) { \
196 			errmsg(__FILE__, __LINE__, (msg), #rc, rc_); \
197 			if( wraptype != Wrap_noalloc ) { mem_act; } \
198 			if( !noabort ) abort(); \
199 		} \
200 	} \
201 }
202 #endif /* LDAP_THREAD_DEBUG_WRAP */
203 
204 #if 0
205 static void
206 warn( const char *file, int line, const char *msg, const char *var, int val )
207 {
208 	fprintf( stderr,
209 		(strpbrk( var, "!=" )
210 		 ? "%s:%d: %s warning: %s\n"
211 		 : "%s:%d: %s warning: %s is %d\n"),
212 		file, line, msg, var, val );
213 }
214 #endif
215 
216 static void
errmsg(const char * file,int line,const char * msg,const char * var,int val)217 errmsg( const char *file, int line, const char *msg, const char *var, int val )
218 {
219 	fprintf( stderr,
220 		(strpbrk( var, "!=" )
221 		 ? "%s:%d: %s error: %s\n"
222 		 : "%s:%d: %s error: %s is %d\n"),
223 		file, line, msg, var, val );
224 }
225 
226 static void
count_resource_leaks(void)227 count_resource_leaks( void )
228 {
229 	int i, j;
230 	char errbuf[200];
231 	if( count == Count_yes ) {
232 		count = Count_reported;
233 #if 0 /* Could break if there are still threads after atexit */
234 		for( i = j = 0; i < Idx_max; i++ )
235 			j |= ldap_int_thread_mutex_destroy( &resource_mutexes[i] );
236 		WARN_IF( j, "ldap_debug_thread_destroy:mutexes" );
237 #endif
238 		for( i = j = 0; i < Idx_max; i++ )
239 			if( resource_counts[i] )
240 				j += sprintf( errbuf + j, ", %d %s",
241 					resource_counts[i], resource_names[i] );
242 		if( j )
243 			fprintf( stderr, "== thr_debug: Leaked%s. ==\n", errbuf + 1 );
244 	}
245 }
246 
247 static void
get_options(void)248 get_options( void )
249 {
250 	static const struct option_info_s {
251 		const char	*name;
252 		int       	*var, val;
253 	} option_info[] = {
254 		{ "off",        &nodebug,  1 },
255 		{ "noabort",    &noabort,  1 },
256 		{ "noerror",    &noerror,  1 },
257 		{ "nocount",    &count,    Count_no },
258 		{ "nosync",     &nosync,   1 },
259 #if LDAP_THREAD_DEBUG_THREAD_ID +0
260 		{ "threadID",   &threadID, 1 },
261 #endif
262 #ifdef LDAP_THREAD_DEBUG_WRAP
263 		{ "nomem",      &nomem,    1 },
264 		{ "noreinit",   &noreinit, 1 },
265 		{ "noalloc",    &wraptype, Wrap_noalloc },
266 		{ "alloc",      &wraptype, Wrap_alloc },
267 		{ "adjptr",     &wraptype, Wrap_adjptr },
268 		{ "scramble",	&wraptype, Wrap_scramble },
269 #endif
270 		{ "tracethreads", &tracethreads, 1 },
271 		{ NULL, NULL, 0 }
272 	};
273 	const char *s = getenv( "LDAP_THREAD_DEBUG" );
274 	if( s != NULL ) {
275 		while( *(s += strspn( s, ", \t\r\n" )) != '\0' ) {
276 			size_t optlen = strcspn( s, ", \t\r\n" );
277 			const struct option_info_s *oi = option_info;
278 			while( oi->name &&
279 				   (strncasecmp( oi->name, s, optlen ) || oi->name[optlen]) )
280 				oi++;
281 			if( oi->name )
282 				*oi->var = oi->val;
283 			else
284 				fprintf( stderr,
285 					"== thr_debug: Unknown $%s option '%.*s' ==\n",
286 					"LDAP_THREAD_DEBUG", (int) optlen, s );
287 			s += optlen;
288 		}
289 	}
290 	if( nodebug ) {
291 		tracethreads = 0;
292 		nosync = noerror = 1;
293 	}
294 	if( nosync )
295 		count = Count_no;
296 	if( noerror )
297 		noabort = 1;
298 #if LDAP_THREAD_DEBUG_THREAD_ID +0
299 	if( nosync )
300 		threadID = 0;
301 #endif
302 #ifdef LDAP_THREAD_DEBUG_WRAP
303 	if( noerror )
304 		nomem = 1;
305 	if( !nomem ) {
306 		static const ldap_debug_usage_info_t usage;
307 		if( sizeof(LDAP_UINTPTR_T) < sizeof(unsigned char *)
308 			|| sizeof(LDAP_UINTPTR_T) < sizeof(ldap_debug_usage_info_t *)
309 			|| UNSCRAMBLE_usagep( SCRAMBLE( &usage ) ) != &usage
310 			|| UNSCRAMBLE_dummyp( SCRAMBLE( (unsigned char *) 0 ) ) )
311 		{
312 			fputs( "== thr_debug: Memory checks unsupported, "
313 				"adding nomem to $LDAP_THREAD_DEBUG ==\n", stderr );
314 			nomem = 1;
315 		}
316 	}
317 	if( nomem ) {
318 		noreinit = 1;
319 		wraptype = Wrap_noalloc;
320 	}
321 	unwrap_offset = -(wrap_offset = (wraptype == Wrap_adjptr));
322 #endif
323 	wrap_threads = (tracethreads || threadID || count);
324 	options_done = 1;
325 }
326 
327 
328 #ifndef LDAP_THREAD_DEBUG_WRAP
329 
330 #define	WRAPPED(ptr)			(ptr)
331 #define	GET_OWNER(ptr)			0
332 #define	SET_OWNER(ptr, thread)	((void) 0)
333 #define	RESET_OWNER(ptr)		((void) 0)
334 #define	ASSERT_OWNER(ptr, msg)	((void) 0)
335 #define	ASSERT_NO_OWNER(ptr, msg) ((void) 0)
336 
337 #define init_usage(ptr, msg)	((void) 0)
338 #define check_usage(ptr, msg)	((void) 0)
339 #define destroy_usage(ptr)		((void) 0)
340 
341 #else /* LDAP_THREAD_DEBUG_WRAP */
342 
343 /* Specialize this if the initializer is not appropriate. */
344 /* The ASSERT_NO_OWNER() definition may also need an override. */
345 #ifndef LDAP_DEBUG_THREAD_NONE
346 #define	LDAP_DEBUG_THREAD_NONE { -1 } /* "no thread" ldap_int_thread_t value */
347 #endif
348 
349 static const ldap_int_thread_t ldap_debug_thread_none = LDAP_DEBUG_THREAD_NONE;
350 
351 #define THREAD_MUTEX_OWNER(mutex) \
352 	ldap_int_thread_equal( (mutex)->owner, ldap_int_thread_self() )
353 
354 void
ldap_debug_thread_assert_mutex_owner(const char * file,int line,const char * msg,ldap_pvt_thread_mutex_t * mutex)355 ldap_debug_thread_assert_mutex_owner(
356 	const char *file,
357 	int line,
358 	const char *msg,
359 	ldap_pvt_thread_mutex_t *mutex )
360 {
361 	if( !(noerror || THREAD_MUTEX_OWNER( mutex )) ) {
362 		errmsg( file, line, msg, "ASSERT_MUTEX_OWNER", 0 );
363 		if( !noabort ) abort();
364 	}
365 }
366 
367 #define	WRAPPED(ptr)			(&(ptr)->wrapped)
368 #define	GET_OWNER(ptr)			((ptr)->owner)
369 #define	SET_OWNER(ptr, thread)	((ptr)->owner = (thread))
370 #define	RESET_OWNER(ptr)		((ptr)->owner = ldap_debug_thread_none)
371 #define	ASSERT_OWNER(ptr, msg)	ERROR_IF( !THREAD_MUTEX_OWNER( ptr ), msg )
372 #ifndef	ASSERT_NO_OWNER
373 #define	ASSERT_NO_OWNER(ptr, msg) ERROR_IF( \
374 	!ldap_int_thread_equal( (ptr)->owner, ldap_debug_thread_none ), msg )
375 #endif
376 
377 /* Try to provoke memory access error (for malloc debuggers) */
378 #define PEEK(mem) {if (-*(volatile const unsigned char *)(mem)) debug_noop();}
379 
380 static void debug_noop( void );
381 static int debug_already_initialized( const ldap_debug_usage_info_t *usage );
382 
383 /* Name used for clearer error message */
384 #define IS_COPY_OR_MOVED(usage) ((usage)->self != SCRAMBLE( usage ))
385 
386 #define DUMMY_ADDR(usage) \
387 	(wraptype == Wrap_scramble \
388 	 ? UNSCRAMBLE_dummyp( (usage)->mem.num ) \
389 	 : (usage)->mem.ptr + unwrap_offset)
390 
391 /* Mark resource as initialized */
392 static void
init_usage(ldap_debug_usage_info_t * usage,const char * msg)393 init_usage( ldap_debug_usage_info_t *usage, const char *msg )
394 {
395 	if( !options_done )
396 		get_options();
397 	if( !nomem ) {
398 		if( !noreinit ) {
399 			MEMERROR_IF( debug_already_initialized( usage ), msg, {
400 				/* Provoke malloc debuggers */
401 				unsigned char *dummy = DUMMY_ADDR( usage );
402 				PEEK( dummy );
403 				free( dummy );
404 				free( dummy );
405 			} );
406 		}
407 		if( wraptype != Wrap_noalloc ) {
408 			unsigned char *dummy = malloc( 1 );
409 			assert( dummy != NULL );
410 			if( wraptype == Wrap_scramble ) {
411 				usage->mem.num = SCRAMBLE( dummy );
412 				/* Verify that ptr<->integer casts work on this host */
413 				assert( UNSCRAMBLE_dummyp( usage->mem.num ) == dummy );
414 			} else {
415 				usage->mem.ptr = dummy + wrap_offset;
416 			}
417 		}
418 	} else {
419 		/* Unused, but set for readability in debugger */
420 		usage->mem.ptr = NULL;
421 	}
422 	usage->self = SCRAMBLE( usage );	/* If nomem, only for debugger */
423 	usage->magic = ldap_debug_magic;
424 	usage->state = ldap_debug_state_inited;
425 }
426 
427 /* Check that resource is initialized and not copied/realloced */
428 static void
check_usage(const ldap_debug_usage_info_t * usage,const char * msg)429 check_usage( const ldap_debug_usage_info_t *usage, const char *msg )
430 {
431 	enum { Is_destroyed = 1 };	/* Name used for clearer error message */
432 
433 	if( usage->magic != ldap_debug_magic ) {
434 		ERROR( usage->magic, msg );
435 		return;
436 	}
437 	switch( usage->state ) {
438 	case ldap_debug_state_destroyed:
439 		MEMERROR_IF( Is_destroyed, msg, {
440 			PEEK( DUMMY_ADDR( usage ) );
441 		} );
442 		break;
443 	default:
444 		ERROR( usage->state, msg );
445 		break;
446 	case ldap_debug_state_inited:
447 		if( !nomem ) {
448 			MEMERROR_IF( IS_COPY_OR_MOVED( usage ), msg, {
449 				PEEK( DUMMY_ADDR( usage ) );
450 				PEEK( UNSCRAMBLE_usagep( usage->self ) );
451 			} );
452 		}
453 		break;
454 	}
455 }
456 
457 /* Mark resource as destroyed. */
458 /* Does not check for errors, call check_usage()/init_usage() first. */
459 static void
destroy_usage(ldap_debug_usage_info_t * usage)460 destroy_usage( ldap_debug_usage_info_t *usage )
461 {
462 	if( usage->state == ldap_debug_state_inited ) {
463 		if( wraptype != Wrap_noalloc ) {
464 			free( DUMMY_ADDR( usage ) );
465 			/* Do not reset the DUMMY_ADDR, leave it for malloc debuggers
466 			 * in case the resource is used after it is freed. */
467 		}
468 		usage->state = ldap_debug_state_destroyed;
469 	}
470 }
471 
472 /* Define these after they are used, so they are hopefully not inlined */
473 
474 static void
debug_noop(void)475 debug_noop( void )
476 {
477 }
478 
479 /*
480  * Valid programs access uninitialized memory here unless "noreinit".
481  *
482  * Returns true if the resource is initialized and not copied/realloced.
483  */
484 LDAP_GCCATTR((noinline))
485 static int
debug_already_initialized(const ldap_debug_usage_info_t * usage)486 debug_already_initialized( const ldap_debug_usage_info_t *usage )
487 {
488 	/*
489 	 * 'ret' keeps the Valgrind warning "Conditional jump or move
490 	 * depends on uninitialised value(s)" _inside_ this function.
491 	 */
492 	volatile int ret = 0;
493 	if( usage->state == ldap_debug_state_inited )
494 		if( !IS_COPY_OR_MOVED( usage ) )
495 	        if( usage->magic == ldap_debug_magic )
496 				ret = 1;
497 	return ret;
498 }
499 
500 #endif /* LDAP_THREAD_DEBUG_WRAP */
501 
502 
503 #if !(LDAP_THREAD_DEBUG_THREAD_ID +0)
504 
505 typedef void ldap_debug_thread_t;
506 #define init_thread_info()	{}
507 #define with_thread_info_lock(statements) { statements; }
508 #define thread_info_detached(t)	0
509 #define add_thread_info(msg, thr, det)	((void) 0)
510 #define remove_thread_info(tinfo, msg)	((void) 0)
511 #define get_thread_info(thread, msg)	NULL
512 
513 #else /* LDAP_THREAD_DEBUG_THREAD_ID */
514 
515 /*
516  * Thread ID tracking.  Currently achieves little.
517  * Should be either expanded or deleted.
518  */
519 
520 /*
521  * Array of threads.  Used instead of making ldap_pvt_thread_t a wrapper
522  * around ldap_int_thread_t, which would slow down ldap_pvt_thread_self().
523  */
524 typedef struct {
525 	ldap_pvt_thread_t           wrapped;
526 	ldap_debug_usage_info_t     usage;
527 	int                         detached;
528 	int                         idx;
529 } ldap_debug_thread_t;
530 
531 static ldap_debug_thread_t      **thread_info;
532 static unsigned int             thread_info_size, thread_info_used;
533 static ldap_int_thread_mutex_t  thread_info_mutex;
534 
535 #define init_thread_info() { \
536 	if( threadID ) { \
537 		int mutex_init_rc = ldap_int_thread_mutex_init( &thread_info_mutex ); \
538 		assert( mutex_init_rc == 0 ); \
539 	} \
540 }
541 
542 #define with_thread_info_lock(statements) { \
543 	int rc_wtl_ = ldap_int_thread_mutex_lock( &thread_info_mutex ); \
544 	assert( rc_wtl_ == 0 ); \
545 	{ statements; } \
546 	rc_wtl_ = ldap_int_thread_mutex_unlock( &thread_info_mutex ); \
547 	assert( rc_wtl_ == 0 ); \
548 }
549 
550 #define thread_info_detached(t) ((t)->detached)
551 
552 static void
add_thread_info(const char * msg,const ldap_pvt_thread_t * thread,int detached)553 add_thread_info(
554 	const char *msg,
555 	const ldap_pvt_thread_t *thread,
556 	int detached )
557 {
558 	ldap_debug_thread_t *t;
559 
560 	if( thread_info_used >= thread_info_size ) {
561 		unsigned int more = thread_info_size + 8;
562 		unsigned int new_size = thread_info_size + more;
563 
564 		t = calloc( more, sizeof(ldap_debug_thread_t) );
565 		assert( t != NULL );
566 		thread_info = realloc( thread_info, new_size * sizeof(*thread_info) );
567 		assert( thread_info != NULL );
568 		do {
569 			t->idx = thread_info_size;
570 			thread_info[thread_info_size++] = t++;
571 		} while( thread_info_size < new_size );
572 	}
573 
574 	t = thread_info[thread_info_used];
575 	init_usage( &t->usage, msg );
576 	t->wrapped = *thread;
577 	t->detached = detached;
578 	thread_info_used++;
579 }
580 
581 static void
remove_thread_info(ldap_debug_thread_t * t,const char * msg)582 remove_thread_info( ldap_debug_thread_t *t, const char *msg )
583 {
584 		ldap_debug_thread_t *last;
585 		int idx;
586 		check_usage( &t->usage, msg );
587 		destroy_usage( &t->usage );
588 		idx = t->idx;
589 		assert( thread_info[idx] == t );
590 		last = thread_info[--thread_info_used];
591 		assert( last->idx == thread_info_used );
592 		(thread_info[idx]              = last)->idx = idx;
593 		(thread_info[thread_info_used] = t   )->idx = thread_info_used;
594 }
595 
596 static ldap_debug_thread_t *
get_thread_info(ldap_pvt_thread_t thread,const char * msg)597 get_thread_info( ldap_pvt_thread_t thread, const char *msg )
598 {
599 	unsigned int i;
600 	ldap_debug_thread_t *t;
601 	for( i = 0; i < thread_info_used; i++ ) {
602 		if( ldap_pvt_thread_equal( thread, thread_info[i]->wrapped ) )
603 			break;
604 	}
605 	ERROR_IF( i == thread_info_used, msg );
606 	t = thread_info[i];
607 	check_usage( &t->usage, msg );
608 	return t;
609 }
610 
611 #endif /* LDAP_THREAD_DEBUG_THREAD_ID */
612 
613 
614 static char *
thread_name(char * buf,int bufsize,ldap_pvt_thread_t thread)615 thread_name( char *buf, int bufsize, ldap_pvt_thread_t thread )
616 {
617 	int i;
618 	--bufsize;
619 	if( bufsize > 2*sizeof(thread) )
620 		bufsize = 2*sizeof(thread);
621 	for( i = 0; i < bufsize; i += 2 )
622 		snprintf( buf+i, 3, "%02x", ((unsigned char *)&thread)[i/2] );
623 	return buf;
624 }
625 
626 
627 /* Add <adjust> (+/-1) to resource count <which> unless "nocount". */
628 static void
adjust_count(int which,int adjust)629 adjust_count( int which, int adjust )
630 {
631 	int rc;
632 	switch( count ) {
633 	case Count_no:
634 		break;
635 	case Count_yes:
636 		rc = ldap_int_thread_mutex_lock( &resource_mutexes[which] );
637 		assert( rc == 0 );
638 		resource_counts[which] += adjust;
639 		rc = ldap_int_thread_mutex_unlock( &resource_mutexes[which] );
640 		assert( rc == 0 );
641 		break;
642 	case Count_reported:
643 		fputs( "== thr_debug: More thread activity after exit ==\n", stderr );
644 		count = Count_reported_more;
645 		/* FALL THROUGH */
646 	case Count_reported_more:
647 		/* Not used, but result might be inspected with debugger */
648 		/* (Hopefully threading is disabled by now...) */
649 		resource_counts[which] += adjust;
650 		break;
651 	}
652 }
653 
654 
655 /* Wrappers for LDAP_THREAD_IMPLEMENTATION: */
656 
657 /* Used instead of ldap_int_thread_initialize by ldap_pvt_thread_initialize */
658 int
ldap_debug_thread_initialize(void)659 ldap_debug_thread_initialize( void )
660 {
661 	int i, rc, rc2;
662 	if( !options_done )
663 		get_options();
664 	ERROR_IF( threading_enabled, "ldap_debug_thread_initialize" );
665 	threading_enabled = 1;
666 	rc = ldap_int_thread_initialize();
667 	if( rc ) {
668 		ERROR( rc, "ldap_debug_thread_initialize:threads" );
669 		threading_enabled = 0;
670 	} else {
671 		init_thread_info();
672 		if( count != Count_no ) {
673 			for( i = rc2 = 0; i < Idx_max; i++ )
674 				rc2 |= ldap_int_thread_mutex_init( &resource_mutexes[i] );
675 			assert( rc2 == 0 );
676 			/* FIXME: Only for static libldap as in init.c? If so, why? */
677 			atexit( count_resource_leaks );
678 		}
679 	}
680 	return rc;
681 }
682 
683 /* Used instead of ldap_int_thread_destroy by ldap_pvt_thread_destroy */
684 int
ldap_debug_thread_destroy(void)685 ldap_debug_thread_destroy( void )
686 {
687 	int rc;
688 	ERROR_IF( !threading_enabled, "ldap_debug_thread_destroy" );
689 	/* sleep(1) -- need to wait for thread pool to finish? */
690 	rc = ldap_int_thread_destroy();
691 	if( rc ) {
692 		ERROR( rc, "ldap_debug_thread_destroy:threads" );
693 	} else {
694 		threading_enabled = 0;
695 	}
696 	return rc;
697 }
698 
699 int
ldap_pvt_thread_set_concurrency(int n)700 ldap_pvt_thread_set_concurrency( int n )
701 {
702 	int rc;
703 	ERROR_IF( !threading_enabled, "ldap_pvt_thread_set_concurrency" );
704 	rc = ldap_int_thread_set_concurrency( n );
705 	ERROR_IF( rc, "ldap_pvt_thread_set_concurrency" );
706 	return rc;
707 }
708 
709 int
ldap_pvt_thread_get_concurrency(void)710 ldap_pvt_thread_get_concurrency( void )
711 {
712 	int rc;
713 	ERROR_IF( !threading_enabled, "ldap_pvt_thread_get_concurrency" );
714 	rc = ldap_int_thread_get_concurrency();
715 	ERROR_IF( rc, "ldap_pvt_thread_get_concurrency" );
716 	return rc;
717 }
718 
719 unsigned int
ldap_pvt_thread_sleep(unsigned int interval)720 ldap_pvt_thread_sleep( unsigned int interval )
721 {
722 	int rc;
723 	ERROR_IF( !threading_enabled, "ldap_pvt_thread_sleep" );
724 	rc = ldap_int_thread_sleep( interval );
725 	ERROR_IF( rc, "ldap_pvt_thread_sleep" );
726 	return 0;
727 }
728 
729 static void
thread_exiting(const char * how,const char * msg)730 thread_exiting( const char *how, const char *msg )
731 {
732 	ldap_pvt_thread_t thread;
733 #if 0 /* Detached threads may exit after ldap_debug_thread_destroy(). */
734 	ERROR_IF( !threading_enabled, msg );
735 #endif
736 	thread = ldap_pvt_thread_self();
737 	if( tracethreads ) {
738 		char buf[40];
739 		fprintf( stderr, "== thr_debug: %s thread %s ==\n",
740 			how, thread_name( buf, sizeof(buf), thread ) );
741 	}
742 	if( threadID ) {
743 		with_thread_info_lock({
744 			ldap_debug_thread_t *t = get_thread_info( thread, msg );
745 			if( thread_info_detached( t ) )
746 				remove_thread_info( t, msg );
747 		});
748 	}
749 	adjust_count( Idx_unexited_thread, -1 );
750 }
751 
752 void
ldap_pvt_thread_exit(void * retval)753 ldap_pvt_thread_exit( void *retval )
754 {
755 	thread_exiting( "Exiting", "ldap_pvt_thread_exit" );
756 	ldap_int_thread_exit( retval );
757 }
758 
759 typedef struct {
760 	void *(*start_routine)( void * );
761 	void *arg;
762 } ldap_debug_thread_call_t;
763 
764 static void *
ldap_debug_thread_wrapper(void * arg)765 ldap_debug_thread_wrapper( void *arg )
766 {
767 	void *ret;
768 	ldap_debug_thread_call_t call = *(ldap_debug_thread_call_t *)arg;
769 	free( arg );
770 	ret = call.start_routine( call.arg );
771 	thread_exiting( "Returning from", "ldap_debug_thread_wrapper" );
772 	return ret;
773 }
774 
775 int
ldap_pvt_thread_create(ldap_pvt_thread_t * thread,int detach,void * (* start_routine)(void *),void * arg)776 ldap_pvt_thread_create(
777 	ldap_pvt_thread_t *thread,
778 	int detach,
779 	void *(*start_routine)( void * ),
780 	void *arg )
781 {
782 	int rc;
783 	if( !options_done )
784 		get_options();
785 	ERROR_IF( !threading_enabled, "ldap_pvt_thread_create" );
786 
787 	if( wrap_threads ) {
788 		ldap_debug_thread_call_t *call = malloc(
789 			sizeof( ldap_debug_thread_call_t ) );
790 		assert( call != NULL );
791 		call->start_routine = start_routine;
792 		call->arg = arg;
793 		start_routine = ldap_debug_thread_wrapper;
794 		arg = call;
795 	}
796 	if( threadID ) {
797 		with_thread_info_lock({
798 			rc = ldap_int_thread_create( thread, detach, start_routine, arg );
799 			if( rc == 0 )
800 				add_thread_info( "ldap_pvt_thread_create", thread, detach );
801 		});
802 	} else {
803 		rc = ldap_int_thread_create( thread, detach, start_routine, arg );
804 	}
805 	if( rc ) {
806 		ERROR( rc, "ldap_pvt_thread_create" );
807 		if( wrap_threads )
808 			free( arg );
809 	} else {
810 		if( tracethreads ) {
811 			char buf[40], buf2[40];
812 			fprintf( stderr,
813 				"== thr_debug: Created thread %s%s from thread %s ==\n",
814 				thread_name( buf, sizeof(buf), *thread ),
815 				detach ? " (detached)" : "",
816 				thread_name( buf2, sizeof(buf2), ldap_pvt_thread_self() ) );
817 		}
818 		adjust_count( Idx_unexited_thread, +1 );
819 		if( !detach )
820 			adjust_count( Idx_unjoined_thread, +1 );
821 	}
822 	return rc;
823 }
824 
825 int
ldap_pvt_thread_join(ldap_pvt_thread_t thread,void ** thread_return)826 ldap_pvt_thread_join( ldap_pvt_thread_t thread, void **thread_return )
827 {
828 	int rc;
829 	ldap_debug_thread_t *t = NULL;
830 	ERROR_IF( !threading_enabled, "ldap_pvt_thread_join" );
831 	if( tracethreads ) {
832 		char buf[40], buf2[40];
833 		fprintf( stderr, "== thr_debug: Joining thread %s in thread %s ==\n",
834 			thread_name( buf, sizeof(buf), thread ),
835 			thread_name( buf2, sizeof(buf2), ldap_pvt_thread_self() ) );
836 	}
837 	if( threadID )
838 		with_thread_info_lock( {
839 			t = get_thread_info( thread, "ldap_pvt_thread_join" );
840 			ERROR_IF( thread_info_detached( t ), "ldap_pvt_thread_join" );
841 		} );
842 	rc = ldap_int_thread_join( thread, thread_return );
843 	if( rc ) {
844 		ERROR( rc, "ldap_pvt_thread_join" );
845 	} else {
846 		if( threadID )
847 			with_thread_info_lock(
848 				remove_thread_info( t, "ldap_pvt_thread_join" ) );
849 		adjust_count( Idx_unjoined_thread, -1 );
850 	}
851 
852 	return rc;
853 }
854 
855 int
ldap_pvt_thread_kill(ldap_pvt_thread_t thread,int signo)856 ldap_pvt_thread_kill( ldap_pvt_thread_t thread, int signo )
857 {
858 	int rc;
859 	ERROR_IF( !threading_enabled, "ldap_pvt_thread_kill" );
860 	if( tracethreads ) {
861 		char buf[40], buf2[40];
862 		fprintf( stderr,
863 			"== thr_debug: Killing thread %s (sig %i) from thread %s ==\n",
864 			thread_name( buf, sizeof(buf), thread ), signo,
865 			thread_name( buf2, sizeof(buf2), ldap_pvt_thread_self() ) );
866 	}
867 	rc = ldap_int_thread_kill( thread, signo );
868 	ERROR_IF( rc, "ldap_pvt_thread_kill" );
869 	return rc;
870 }
871 
872 int
ldap_pvt_thread_yield(void)873 ldap_pvt_thread_yield( void )
874 {
875 	int rc;
876 	ERROR_IF( !threading_enabled, "ldap_pvt_thread_yield" );
877 	rc = ldap_int_thread_yield();
878 	ERROR_IF( rc, "ldap_pvt_thread_yield" );
879 	return rc;
880 }
881 
882 ldap_pvt_thread_t
ldap_pvt_thread_self(void)883 ldap_pvt_thread_self( void )
884 {
885 #if 0 /* Function is used by ch_free() via slap_sl_contxt() in slapd */
886 	ERROR_IF( !threading_enabled, "ldap_pvt_thread_self" );
887 #endif
888 	return ldap_int_thread_self();
889 }
890 
891 int
ldap_pvt_thread_cond_init(ldap_pvt_thread_cond_t * cond)892 ldap_pvt_thread_cond_init( ldap_pvt_thread_cond_t *cond )
893 {
894 	int rc;
895 	init_usage( &cond->usage, "ldap_pvt_thread_cond_init" );
896 	rc = ldap_int_thread_cond_init( WRAPPED( cond ) );
897 	if( rc ) {
898 		ERROR( rc, "ldap_pvt_thread_cond_init" );
899 		destroy_usage( &cond->usage );
900 	} else {
901 		adjust_count( Idx_cond, +1 );
902 	}
903 	return rc;
904 }
905 
906 int
ldap_pvt_thread_cond_destroy(ldap_pvt_thread_cond_t * cond)907 ldap_pvt_thread_cond_destroy( ldap_pvt_thread_cond_t *cond )
908 {
909 	int rc;
910 	check_usage( &cond->usage, "ldap_pvt_thread_cond_destroy" );
911 	rc = ldap_int_thread_cond_destroy( WRAPPED( cond ) );
912 	if( rc ) {
913 		ERROR( rc, "ldap_pvt_thread_cond_destroy" );
914 	} else {
915 		destroy_usage( &cond->usage );
916 		adjust_count( Idx_cond, -1 );
917 	}
918 	return rc;
919 }
920 
921 int
ldap_pvt_thread_cond_signal(ldap_pvt_thread_cond_t * cond)922 ldap_pvt_thread_cond_signal( ldap_pvt_thread_cond_t *cond )
923 {
924 	int rc;
925 	check_usage( &cond->usage, "ldap_pvt_thread_cond_signal" );
926 	rc = ldap_int_thread_cond_signal( WRAPPED( cond ) );
927 	ERROR_IF( rc, "ldap_pvt_thread_cond_signal" );
928 	return rc;
929 }
930 
931 int
ldap_pvt_thread_cond_broadcast(ldap_pvt_thread_cond_t * cond)932 ldap_pvt_thread_cond_broadcast( ldap_pvt_thread_cond_t *cond )
933 {
934 	int rc;
935 	check_usage( &cond->usage, "ldap_pvt_thread_cond_broadcast" );
936 	rc = ldap_int_thread_cond_broadcast( WRAPPED( cond ) );
937 	ERROR_IF( rc, "ldap_pvt_thread_cond_broadcast" );
938 	return rc;
939 }
940 
941 int
ldap_pvt_thread_cond_wait(ldap_pvt_thread_cond_t * cond,ldap_pvt_thread_mutex_t * mutex)942 ldap_pvt_thread_cond_wait(
943 	ldap_pvt_thread_cond_t *cond,
944 	ldap_pvt_thread_mutex_t *mutex )
945 {
946 	int rc;
947 	ldap_int_thread_t owner;
948 	check_usage( &cond->usage, "ldap_pvt_thread_cond_wait:cond" );
949 	check_usage( &mutex->usage, "ldap_pvt_thread_cond_wait:mutex" );
950 	adjust_count( Idx_locked_mutex, -1 );
951 	owner = GET_OWNER( mutex );
952 	ASSERT_OWNER( mutex, "ldap_pvt_thread_cond_wait" );
953 	RESET_OWNER( mutex );
954 	rc = ldap_int_thread_cond_wait( WRAPPED( cond ), WRAPPED( mutex ) );
955 	ASSERT_NO_OWNER( mutex, "ldap_pvt_thread_cond_wait" );
956 	SET_OWNER( mutex, rc ? owner : ldap_int_thread_self() );
957 	adjust_count( Idx_locked_mutex, +1 );
958 	ERROR_IF( rc, "ldap_pvt_thread_cond_wait" );
959 	return rc;
960 }
961 
962 int
ldap_pvt_thread_mutex_recursive_init(ldap_pvt_thread_mutex_t * mutex)963 ldap_pvt_thread_mutex_recursive_init( ldap_pvt_thread_mutex_t *mutex )
964 {
965 	int rc;
966 	init_usage( &mutex->usage, "ldap_pvt_thread_mutex_recursive_init" );
967 	rc = ldap_int_thread_mutex_recursive_init( WRAPPED( mutex ) );
968 	if( rc ) {
969 		ERROR( rc, "ldap_pvt_thread_mutex_recursive_init" );
970 		destroy_usage( &mutex->usage );
971 	} else {
972 		RESET_OWNER( mutex );
973 		adjust_count( Idx_mutex, +1 );
974 	}
975 	return rc;
976 }
977 
978 int
ldap_pvt_thread_mutex_init(ldap_pvt_thread_mutex_t * mutex)979 ldap_pvt_thread_mutex_init( ldap_pvt_thread_mutex_t *mutex )
980 {
981 	int rc;
982 	init_usage( &mutex->usage, "ldap_pvt_thread_mutex_init" );
983 	rc = ldap_int_thread_mutex_init( WRAPPED( mutex ) );
984 	if( rc ) {
985 		ERROR( rc, "ldap_pvt_thread_mutex_init" );
986 		destroy_usage( &mutex->usage );
987 	} else {
988 		RESET_OWNER( mutex );
989 		adjust_count( Idx_mutex, +1 );
990 	}
991 	return rc;
992 }
993 
994 int
ldap_pvt_thread_mutex_destroy(ldap_pvt_thread_mutex_t * mutex)995 ldap_pvt_thread_mutex_destroy( ldap_pvt_thread_mutex_t *mutex )
996 {
997 	int rc;
998 	check_usage( &mutex->usage, "ldap_pvt_thread_mutex_destroy" );
999 	ASSERT_NO_OWNER( mutex, "ldap_pvt_thread_mutex_destroy" );
1000 	rc = ldap_int_thread_mutex_destroy( WRAPPED( mutex ) );
1001 	if( rc ) {
1002 		ERROR( rc, "ldap_pvt_thread_mutex_destroy" );
1003 	} else {
1004 		destroy_usage( &mutex->usage );
1005 		RESET_OWNER( mutex );
1006 		adjust_count( Idx_mutex, -1 );
1007 	}
1008 	return rc;
1009 }
1010 
1011 int
ldap_pvt_thread_mutex_lock(ldap_pvt_thread_mutex_t * mutex)1012 ldap_pvt_thread_mutex_lock( ldap_pvt_thread_mutex_t *mutex )
1013 {
1014 	int rc;
1015 	check_usage( &mutex->usage, "ldap_pvt_thread_mutex_lock" );
1016 	rc = ldap_int_thread_mutex_lock( WRAPPED( mutex ) );
1017 	if( rc ) {
1018 		ERROR_IF( rc, "ldap_pvt_thread_mutex_lock" );
1019 	} else {
1020 		ASSERT_NO_OWNER( mutex, "ldap_pvt_thread_mutex_lock" );
1021 		SET_OWNER( mutex, ldap_int_thread_self() );
1022 		adjust_count( Idx_locked_mutex, +1 );
1023 	}
1024 	return rc;
1025 }
1026 
1027 int
ldap_pvt_thread_mutex_trylock(ldap_pvt_thread_mutex_t * mutex)1028 ldap_pvt_thread_mutex_trylock( ldap_pvt_thread_mutex_t *mutex )
1029 {
1030 	int rc;
1031 	check_usage( &mutex->usage, "ldap_pvt_thread_mutex_trylock" );
1032 	rc = ldap_int_thread_mutex_trylock( WRAPPED( mutex ) );
1033 	if( rc == 0 ) {
1034 		ASSERT_NO_OWNER( mutex, "ldap_pvt_thread_mutex_trylock" );
1035 		SET_OWNER( mutex, ldap_int_thread_self() );
1036 		adjust_count( Idx_locked_mutex, +1 );
1037 	}
1038 	return rc;
1039 }
1040 
1041 int
ldap_pvt_thread_mutex_unlock(ldap_pvt_thread_mutex_t * mutex)1042 ldap_pvt_thread_mutex_unlock( ldap_pvt_thread_mutex_t *mutex )
1043 {
1044 	int rc;
1045 	check_usage( &mutex->usage, "ldap_pvt_thread_mutex_unlock" );
1046 	ASSERT_OWNER( mutex, "ldap_pvt_thread_mutex_unlock" );
1047 	RESET_OWNER( mutex ); /* Breaks if this thread did not own the mutex */
1048 	rc = ldap_int_thread_mutex_unlock( WRAPPED( mutex ) );
1049 	if( rc ) {
1050 		ERROR_IF( rc, "ldap_pvt_thread_mutex_unlock" );
1051 	} else {
1052 		adjust_count( Idx_locked_mutex, -1 );
1053 	}
1054 	return rc;
1055 }
1056 
1057 
1058 /* Wrappers for LDAP_THREAD_RDWR_IMPLEMENTATION: */
1059 
1060 int
ldap_pvt_thread_rdwr_init(ldap_pvt_thread_rdwr_t * rwlock)1061 ldap_pvt_thread_rdwr_init( ldap_pvt_thread_rdwr_t *rwlock )
1062 {
1063 	int rc;
1064 	init_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_init" );
1065 	rc = ldap_int_thread_rdwr_init( WRAPPED( rwlock ) );
1066 	if( rc ) {
1067 		ERROR( rc, "ldap_pvt_thread_rdwr_init" );
1068 		destroy_usage( &rwlock->usage );
1069 	} else {
1070 		adjust_count( Idx_rdwr, +1 );
1071 	}
1072 	return rc;
1073 }
1074 
1075 int
ldap_pvt_thread_rdwr_destroy(ldap_pvt_thread_rdwr_t * rwlock)1076 ldap_pvt_thread_rdwr_destroy( ldap_pvt_thread_rdwr_t *rwlock )
1077 {
1078 	int rc;
1079 	check_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_destroy" );
1080 	rc = ldap_int_thread_rdwr_destroy( WRAPPED( rwlock ) );
1081 	if( rc ) {
1082 		ERROR( rc, "ldap_pvt_thread_rdwr_destroy" );
1083 	} else {
1084 		destroy_usage( &rwlock->usage );
1085 		adjust_count( Idx_rdwr, -1 );
1086 	}
1087 	return rc;
1088 }
1089 
1090 int
ldap_pvt_thread_rdwr_rlock(ldap_pvt_thread_rdwr_t * rwlock)1091 ldap_pvt_thread_rdwr_rlock( ldap_pvt_thread_rdwr_t *rwlock )
1092 {
1093 	int rc;
1094 	check_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_rlock" );
1095 	rc = ldap_int_thread_rdwr_rlock( WRAPPED( rwlock ) );
1096 	ERROR_IF( rc, "ldap_pvt_thread_rdwr_rlock" );
1097 	return rc;
1098 }
1099 
1100 int
ldap_pvt_thread_rdwr_rtrylock(ldap_pvt_thread_rdwr_t * rwlock)1101 ldap_pvt_thread_rdwr_rtrylock( ldap_pvt_thread_rdwr_t *rwlock )
1102 {
1103 	check_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_rtrylock" );
1104 	return ldap_int_thread_rdwr_rtrylock( WRAPPED( rwlock ) );
1105 }
1106 
1107 int
ldap_pvt_thread_rdwr_runlock(ldap_pvt_thread_rdwr_t * rwlock)1108 ldap_pvt_thread_rdwr_runlock( ldap_pvt_thread_rdwr_t *rwlock )
1109 {
1110 	int rc;
1111 	check_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_runlock" );
1112 	rc = ldap_int_thread_rdwr_runlock( WRAPPED( rwlock ) );
1113 	ERROR_IF( rc, "ldap_pvt_thread_rdwr_runlock" );
1114 	return rc;
1115 }
1116 
1117 int
ldap_pvt_thread_rdwr_wlock(ldap_pvt_thread_rdwr_t * rwlock)1118 ldap_pvt_thread_rdwr_wlock( ldap_pvt_thread_rdwr_t *rwlock )
1119 {
1120 	int rc;
1121 	check_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_wlock" );
1122 	rc = ldap_int_thread_rdwr_wlock( WRAPPED( rwlock ) );
1123 	ERROR_IF( rc, "ldap_pvt_thread_rdwr_wlock" );
1124 	return rc;
1125 }
1126 
1127 int
ldap_pvt_thread_rdwr_wtrylock(ldap_pvt_thread_rdwr_t * rwlock)1128 ldap_pvt_thread_rdwr_wtrylock( ldap_pvt_thread_rdwr_t *rwlock )
1129 {
1130 	check_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_wtrylock" );
1131 	return ldap_int_thread_rdwr_wtrylock( WRAPPED( rwlock ) );
1132 }
1133 
1134 int
ldap_pvt_thread_rdwr_wunlock(ldap_pvt_thread_rdwr_t * rwlock)1135 ldap_pvt_thread_rdwr_wunlock( ldap_pvt_thread_rdwr_t *rwlock )
1136 {
1137 	int rc;
1138 	check_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_wunlock" );
1139 	rc = ldap_int_thread_rdwr_wunlock( WRAPPED( rwlock ) );
1140 	ERROR_IF( rc, "ldap_pvt_thread_rdwr_wunlock" );
1141 	return rc;
1142 }
1143 
1144 #if defined(LDAP_RDWR_DEBUG) && !defined(LDAP_THREAD_HAVE_RDWR)
1145 
1146 int
ldap_pvt_thread_rdwr_readers(ldap_pvt_thread_rdwr_t * rwlock)1147 ldap_pvt_thread_rdwr_readers( ldap_pvt_thread_rdwr_t *rwlock )
1148 {
1149 	check_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_readers" );
1150 	return ldap_int_thread_rdwr_readers( WRAPPED( rwlock ) );
1151 }
1152 
1153 int
ldap_pvt_thread_rdwr_writers(ldap_pvt_thread_rdwr_t * rwlock)1154 ldap_pvt_thread_rdwr_writers( ldap_pvt_thread_rdwr_t *rwlock )
1155 {
1156 	check_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_writers" );
1157 	return ldap_int_thread_rdwr_writers( WRAPPED( rwlock ) );
1158 }
1159 
1160 int
ldap_pvt_thread_rdwr_active(ldap_pvt_thread_rdwr_t * rwlock)1161 ldap_pvt_thread_rdwr_active( ldap_pvt_thread_rdwr_t *rwlock )
1162 {
1163 	check_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_active" );
1164 	return ldap_int_thread_rdwr_active( WRAPPED( rwlock ) );
1165 }
1166 
1167 #endif /* LDAP_RDWR_DEBUG && !LDAP_THREAD_HAVE_RDWR */
1168 
1169 
1170 /* Some wrappers for LDAP_THREAD_POOL_IMPLEMENTATION: */
1171 #ifdef LDAP_THREAD_POOL_IMPLEMENTATION
1172 
1173 int
ldap_pvt_thread_pool_init(ldap_pvt_thread_pool_t * tpool,int max_threads,int max_pending)1174 ldap_pvt_thread_pool_init(
1175 	ldap_pvt_thread_pool_t *tpool,
1176 	int max_threads,
1177 	int max_pending )
1178 {
1179 	int rc;
1180 	if( !options_done )
1181 		get_options();
1182 	ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_init" );
1183 	rc = ldap_int_thread_pool_init( tpool, max_threads, max_pending );
1184 	if( rc ) {
1185 		ERROR( rc, "ldap_pvt_thread_pool_init" );
1186 	} else {
1187 		adjust_count( Idx_tpool, +1 );
1188 	}
1189 	return rc;
1190 }
1191 
1192 int
ldap_pvt_thread_pool_submit(ldap_pvt_thread_pool_t * tpool,ldap_pvt_thread_start_t * start_routine,void * arg)1193 ldap_pvt_thread_pool_submit(
1194 	ldap_pvt_thread_pool_t *tpool,
1195 	ldap_pvt_thread_start_t *start_routine, void *arg )
1196 {
1197 	int rc, has_pool;
1198 	ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_submit" );
1199 	has_pool = (tpool && *tpool);
1200 	rc = ldap_int_thread_pool_submit( tpool, start_routine, arg );
1201 	if( has_pool )
1202 		ERROR_IF( rc, "ldap_pvt_thread_pool_submit" );
1203 	return rc;
1204 }
1205 
1206 int
ldap_pvt_thread_pool_maxthreads(ldap_pvt_thread_pool_t * tpool,int max_threads)1207 ldap_pvt_thread_pool_maxthreads(
1208 	ldap_pvt_thread_pool_t *tpool,
1209 	int max_threads )
1210 {
1211 	ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_maxthreads" );
1212 	return ldap_int_thread_pool_maxthreads(	tpool, max_threads );
1213 }
1214 
1215 int
ldap_pvt_thread_pool_backload(ldap_pvt_thread_pool_t * tpool)1216 ldap_pvt_thread_pool_backload( ldap_pvt_thread_pool_t *tpool )
1217 {
1218 	ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_backload" );
1219 	return ldap_int_thread_pool_backload( tpool );
1220 }
1221 
1222 int
ldap_pvt_thread_pool_destroy(ldap_pvt_thread_pool_t * tpool,int run_pending)1223 ldap_pvt_thread_pool_destroy( ldap_pvt_thread_pool_t *tpool, int run_pending )
1224 {
1225 	int rc, has_pool;
1226 	ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_destroy" );
1227 	has_pool = (tpool && *tpool);
1228 	rc = ldap_int_thread_pool_destroy( tpool, run_pending );
1229 	if( has_pool ) {
1230 		if( rc ) {
1231 			ERROR( rc, "ldap_pvt_thread_pool_destroy" );
1232 		} else {
1233 			adjust_count( Idx_tpool, -1 );
1234 		}
1235 	}
1236 	return rc;
1237 }
1238 
1239 int
ldap_pvt_thread_pool_close(ldap_pvt_thread_pool_t * tpool,int run_pending)1240 ldap_pvt_thread_pool_close( ldap_pvt_thread_pool_t *tpool, int run_pending )
1241 {
1242 	int rc, has_pool;
1243 	ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_close" );
1244 	has_pool = (tpool && *tpool);
1245 	rc = ldap_int_thread_pool_close( tpool, run_pending );
1246 	if( has_pool && rc ) {
1247 		ERROR( rc, "ldap_pvt_thread_pool_close" );
1248 	}
1249 	return rc;
1250 }
1251 
1252 int
ldap_pvt_thread_pool_free(ldap_pvt_thread_pool_t * tpool)1253 ldap_pvt_thread_pool_free( ldap_pvt_thread_pool_t *tpool )
1254 {
1255 	int rc, has_pool;
1256 	ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_free" );
1257 	has_pool = (tpool && *tpool);
1258 	rc = ldap_int_thread_pool_free( tpool );
1259 	if( has_pool ) {
1260 		if( rc ) {
1261 			ERROR( rc, "ldap_pvt_thread_pool_free" );
1262 		} else {
1263 			adjust_count( Idx_tpool, -1 );
1264 		}
1265 	}
1266 	return rc;
1267 }
1268 
1269 int
ldap_pvt_thread_pool_pause(ldap_pvt_thread_pool_t * tpool)1270 ldap_pvt_thread_pool_pause( ldap_pvt_thread_pool_t *tpool )
1271 {
1272 	ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_pause" );
1273 	return ldap_int_thread_pool_pause( tpool );
1274 }
1275 
1276 int
ldap_pvt_thread_pool_resume(ldap_pvt_thread_pool_t * tpool)1277 ldap_pvt_thread_pool_resume( ldap_pvt_thread_pool_t *tpool )
1278 {
1279 	ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_resume" );
1280 	return ldap_int_thread_pool_resume( tpool );
1281 }
1282 
1283 int
ldap_pvt_thread_pool_getkey(void * xctx,void * key,void ** data,ldap_pvt_thread_pool_keyfree_t ** kfree)1284 ldap_pvt_thread_pool_getkey(
1285 	void *xctx,
1286 	void *key,
1287 	void **data,
1288 	ldap_pvt_thread_pool_keyfree_t **kfree )
1289 {
1290 #if 0 /* Function is used by ch_free() via slap_sl_contxt() in slapd */
1291 	ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_getkey" );
1292 #endif
1293 	return ldap_int_thread_pool_getkey( xctx, key, data, kfree );
1294 }
1295 
1296 int
ldap_pvt_thread_pool_setkey(void * xctx,void * key,void * data,ldap_pvt_thread_pool_keyfree_t * kfree,void ** olddatap,ldap_pvt_thread_pool_keyfree_t ** oldkfreep)1297 ldap_pvt_thread_pool_setkey(
1298 	void *xctx,
1299 	void *key,
1300 	void *data,
1301 	ldap_pvt_thread_pool_keyfree_t *kfree,
1302 	void **olddatap,
1303 	ldap_pvt_thread_pool_keyfree_t **oldkfreep )
1304 {
1305 	int rc;
1306 	ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_setkey" );
1307 	rc = ldap_int_thread_pool_setkey(
1308 		xctx, key, data, kfree, olddatap, oldkfreep );
1309 	ERROR_IF( rc, "ldap_pvt_thread_pool_setkey" );
1310 	return rc;
1311 }
1312 
1313 void
ldap_pvt_thread_pool_purgekey(void * key)1314 ldap_pvt_thread_pool_purgekey( void *key )
1315 {
1316 	ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_purgekey" );
1317 	ldap_int_thread_pool_purgekey( key );
1318 }
1319 
1320 void *
ldap_pvt_thread_pool_context(void)1321 ldap_pvt_thread_pool_context( void )
1322 {
1323 #if 0 /* Function is used by ch_free() via slap_sl_contxt() in slapd */
1324 	ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_context" );
1325 #endif
1326 	return ldap_int_thread_pool_context();
1327 }
1328 
1329 void
ldap_pvt_thread_pool_context_reset(void * vctx)1330 ldap_pvt_thread_pool_context_reset( void *vctx )
1331 {
1332 	ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_context_reset" );
1333 	ldap_int_thread_pool_context_reset( vctx );
1334 }
1335 
1336 #endif /* LDAP_THREAD_POOL_IMPLEMENTATION */
1337 
1338 #endif /* LDAP_THREAD_DEBUG */
1339