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