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