]> git.sur5r.net Git - openldap/blob - libraries/libldap_r/thr_debug.c
Import ITS#4972 changes local to thr_debug.c from HEAD.
[openldap] / libraries / libldap_r / thr_debug.c
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-2007 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 three types of thread operation debugging:
19  *
20  * - Print error messages and abort() when thread operations fail:
21  *   Operations on threads, mutexes, condition variables, rdwr locks.
22  *   Some thread pool operations are also checked, but not those for
23  *   which failure can happen in normal slapd operation.
24  *
25  * - Wrap those types except threads and pools in structs that
26  *   contain a state variable or a pointer to dummy allocated memory,
27  *   and check that on all operations.  The dummy memory variant lets
28  *   malloc debuggers see some incorrect use as memory leaks, access
29  *   to freed memory, etc.
30  *
31  * - Print a count of leaked thread resources after cleanup.
32  *
33  * Compile-time (./configure) setup:  Macros defined in CPPFLAGS.
34  *
35  *   LDAP_THREAD_DEBUG or LDAP_THREAD_DEBUG=2
36  *      Enables debugging, but value & 2 turns off type wrapping.
37  *
38  *   LDAP_UINTPTR_T=integer type to hold pointers, preferably unsigned.
39  *      Used by dummy memory option "scramble". Default = unsigned long.
40  *
41  *   In addition, you may need to set up an implementation-specific way
42  *      to enable whatever error checking your thread library provides.
43  *      Currently only implemented for Posix threads (pthreads), where
44  *      you may need to define LDAP_INT_THREAD_MUTEXATTR.  The default
45  *      is PTHREAD_MUTEX_ERRORCHECK, or PTHREAD_MUTEX_ERRORCHECK_NP for
46  *      Linux threads.  See pthread_mutexattr_settype(3).
47  *
48  * Run-time configuration:  Environment variable LDAP_THREAD_DEBUG.
49  *
50  *   The variable may contain a comma- or space-separated option list.
51  *   Options:
52  *      off      - Disable this package.
53  *   Error checking:
54  *      noabort  - Do not abort() on errors.
55  *      noerror  - Do not report errors.  Implies noabort.
56  *      nocount  - Do not report counts of unreleased resources.
57  *   State variable/dummy memory, unless type wrapping is disabled:
58  *      noalloc  - Default.  Use a state variable, not dummy memory.
59  *      dupinit  - Implies noalloc.  Check if resources that have
60  *                 not been destroyed are reinitialized.  Tools that
61  *                 report uninitialized memory access should disable
62  *                 such warnings about debug_already_initialized().
63  *      alloc    - Allocate dummy memory and store pointers as-is.
64  *                 Malloc debuggers might not notice unreleased
65  *                 resources in global variables as memory leaks.
66  *      scramble - Store bitwise complement of dummy memory pointer.
67  *                 That never escapes memory leak detectors -
68  *                 but detection while the program is running will
69  *                 report active resources as leaks.  Do not
70  *                 use this if a garbage collector is in use:-)
71  *      adjptr   - Point to end of dummy memory.
72  *                 Purify reports these as "potential leaks" (PLK).
73  *                 I have not checked other malloc debuggers.
74  *   Tracing:
75  *      tracethreads - Report create/join/exit/kill of threads.
76  */
77
78 #include "portable.h"
79
80 #if defined( LDAP_THREAD_DEBUG )
81
82 #include <stdio.h>
83 #include <ac/errno.h>
84 #include <ac/stdlib.h>
85 #include <ac/string.h>
86
87 #include "ldap_pvt_thread.h" /* Get the thread interface */
88 #define LDAP_THREAD_IMPLEMENTATION
89 #define LDAP_THREAD_DEBUG_IMPLEMENTATION
90 #define LDAP_THREAD_RDWR_IMPLEMENTATION
91 #define LDAP_THREAD_POOL_IMPLEMENTATION
92 #include "ldap_thr_debug.h"  /* Get the underlying implementation */
93
94
95 /* Options from environment variable $LDAP_THREAD_DEBUG */
96 enum { Count_no = 0, Count_yes, Count_reported, Count_reported_more };
97 static int nodebug, noabort, noerror, count = Count_yes, options_done;
98 #ifdef LDAP_THREAD_DEBUG_WRAP
99 enum { Wrap_noalloc, Wrap_alloc, Wrap_scramble, Wrap_adjptr };
100 static int dupinit, wraptype = Wrap_noalloc, wrap_offset, unwrap_offset;
101 #endif
102 static int tracethreads;
103
104 static int threading_enabled;
105
106 enum {
107         Idx_unexited_thread, Idx_unjoined_thread, Idx_locked_mutex,
108         Idx_mutex, Idx_cond, Idx_rdwr, Idx_tpool, Idx_max
109 };
110 static int resource_counts[Idx_max];
111 static const char *const resource_names[] = {
112         "unexited threads", "unjoined threads", "locked mutexes",
113         "mutexes", "conds", "rdwrs", "thread pools"
114 };
115 static ldap_int_thread_mutex_t resource_mutexes[Idx_max];
116
117
118 /*
119  * Making ldap_pvt_thread_t a wrapper around ldap_int_thread_t would
120  * slow down ldap_pvt_thread_self(), so keep a list of threads instead.
121  */
122 typedef struct ldap_debug_thread_s {
123         ldap_pvt_thread_t                       wrapped;
124         ldap_debug_usage_info_t         usage;
125         int                                                     detached;
126         int                                                     freeme, idx;
127 } ldap_debug_thread_t;
128
129 static ldap_debug_thread_t              **thread_info;
130 static unsigned int                             thread_info_size, thread_info_used;
131 static ldap_int_thread_mutex_t  thread_info_mutex;
132
133
134 #define WARN(var, msg)   (warn (__FILE__, __LINE__, (msg), #var, (var)))
135 #define ERROR(var,msg)   (error(__FILE__, __LINE__, (msg), #var, (var)))
136 #define WARN_IF(rc, msg) {if (rc) warn (__FILE__, __LINE__, (msg), #rc, (rc));}
137 #define ERROR_IF(rc,msg) {if (rc) error(__FILE__, __LINE__, (msg), #rc, (rc));}
138
139 #if 0
140 static void
141 warn( const char *file, int line, const char *msg, const char *var, int val )
142 {
143         fprintf( stderr, "%s:%d: %s warning: %s is %d\n",
144                 file, line, msg, var, val );
145 }
146 #endif
147
148 static void
149 error( const char *file, int line, const char *msg, const char *var, int val )
150 {
151         if( !noerror ) {
152                 fprintf( stderr, "%s:%d: %s error: %s is %d\n",
153                         file, line, msg, var, val );
154                 if( !noabort )
155                         abort();
156         }
157 }
158
159 static void
160 count_resource_leaks( void )
161 {
162         int i, j;
163         char errbuf[200], *delim = "Leaked";
164         if( count == Count_yes ) {
165                 count = Count_reported;
166 #if 0 /* Could break if there are still threads after atexit */
167                 for( i = j = 0; i < Idx_max; i++ )
168                         j |= ldap_int_thread_mutex_destroy( &resource_mutexes[i] );
169                 WARN_IF( j, "ldap_debug_thread_destroy:mutexes" );
170 #endif
171                 for( i = j = 0; i < Idx_max; i++ ) {
172                         if( resource_counts[i] ) {
173                                 j += sprintf( errbuf + j, "%s %d %s",
174                                         delim, resource_counts[i], resource_names[i] );
175                                 delim = ",";
176                         }
177                 }
178                 if( j )
179                         fprintf( stderr, "%s:%d: %s.\n", __FILE__, __LINE__, errbuf );
180         }
181 }
182
183 static void
184 get_options( void )
185 {
186         static const struct option_info_s {
187                 const char      *name;
188                 int             *var, val;
189         } option_info[] = {
190                 { "off",        &nodebug,  1 },
191                 { "noabort",    &noabort,  1 },
192                 { "noerror",    &noerror,  1 },
193                 { "nocount",    &count,    Count_no },
194 #ifdef LDAP_THREAD_DEBUG_WRAP
195                 { "noalloc",    &wraptype, Wrap_noalloc },
196                 { "dupinit",    &dupinit,  1 },
197                 { "alloc",      &wraptype, Wrap_alloc },
198                 { "adjptr",     &wraptype, Wrap_adjptr },
199                 { "scramble",   &wraptype, Wrap_scramble },
200 #endif
201                 { "tracethreads", &tracethreads, 1 },
202                 { NULL, NULL, 0 }
203         };
204         const char *s = getenv( "LDAP_THREAD_DEBUG" );
205         if( s != NULL ) {
206                 while( *(s += strspn( s, ", \t\r\n" )) != '\0' ) {
207                         size_t optlen = strcspn( s, ", \t\r\n" );
208                         const struct option_info_s *oi = option_info;
209                         while( oi->name &&
210                                    (strncasecmp( oi->name, s, optlen ) || oi->name[optlen]) )
211                                 oi++;
212                         if( oi->name )
213                                 *oi->var = oi->val;
214                         else
215                                 fprintf( stderr, "Unknown $%s option '%.*s'\n",
216                                         "LDAP_THREAD_DEBUG", (int) optlen, s );
217                         s += optlen;
218                 }
219         }
220         if( nodebug ) {
221                 noabort = noerror = 1;
222                 tracethreads = dupinit = 0;
223                 count = Count_no;
224         }
225 #ifdef LDAP_THREAD_DEBUG_WRAP
226         if( nodebug || dupinit ) {
227                 wraptype = Wrap_noalloc;
228         } else if( wraptype == Wrap_scramble ) {
229                 const unsigned char *dummy = (const unsigned char *)&option_info;
230                 if( sizeof(LDAP_UINTPTR_T) < sizeof(void *)
231                         || (unsigned char *)~~(LDAP_UINTPTR_T) dummy != dummy
232                         || (unsigned char *)~~(LDAP_UINTPTR_T) (unsigned char *)0 )
233                 {
234                         fprintf( stderr, "Misconfigured for $%s %s.  Using %s.\n",
235                                 "LDAP_THREAD_DEBUG", "scramble", "adjptr" );
236                         wraptype = Wrap_adjptr;
237                 }
238         }
239         unwrap_offset = -(wrap_offset = (wraptype == Wrap_adjptr));
240 #endif
241         options_done = 1;
242 }
243
244
245 static char *
246 thread_name( char *buf, int bufsize, ldap_pvt_thread_t thread )
247 {
248         int i;
249         --bufsize;
250         if( bufsize > 2*sizeof(thread) )
251                 bufsize = 2*sizeof(thread);
252         for( i = 0; i < bufsize; i += 2 )
253                 snprintf( buf+i, 3, "%02x", ((unsigned char *)&thread)[i/2] );
254         return buf;
255 }
256
257 static void
258 exit_thread_message( ldap_pvt_thread_t thread )
259 {
260         if( tracethreads ) {
261                 char buf[40];
262                 fprintf( stderr, "== Exiting thread %s ==\n",
263                         thread_name( buf, sizeof(buf), thread ) );
264         }
265 }
266
267
268 #ifndef LDAP_THREAD_DEBUG_WRAP
269
270 #define WRAPPED(ptr)                    (ptr)
271 #define alloc_usage(ptr, msg)   ((void) 0)
272 #define check_usage(ptr, msg)   ((void) 0)
273 #define free_usage(ptr, msg)    ((void) 0)
274
275 #define with_threads_lock(statement)    { statement; }
276 #define get_new_thread_info(msg)                NULL
277 #define update_thread_info(ti, th, det) {}
278 #define remove_thread_info(ti, msg)             ((void)0)
279 #define get_thread_info(thread, msg)    NULL
280 #define exiting_thread(msg)     exit_thread_message(ldap_pvt_thread_self())
281
282 #else /* LDAP_THREAD_DEBUG_WRAP */
283
284 #define WRAPPED(ptr)                    (&(ptr)->wrapped)
285
286 #define INITED_VALUE            0x12345678UL
287 #define INITED_BYTE_VALUE       0xd5
288
289 /* Valid programs will access uninitialized memory here if dupinit. */
290 static int
291 debug_already_initialized( const LDAP_UINTPTR_T *num )
292 {
293         /*
294          * 'ret' keeps the Valgrind warning "Conditional jump or move
295          * depends on uninitialised value(s)" _inside_ this function.
296          */
297         volatile int ret = 0;
298         if( dupinit && *num == INITED_VALUE )
299                 ret = 1;
300         return ret;
301 }
302
303 static void
304 alloc_usage( ldap_debug_usage_info_t *usage, const char *msg )
305 {
306         if( !options_done )
307                 get_options();
308         if( wraptype == Wrap_noalloc ) {
309                 ERROR_IF( debug_already_initialized( &usage->num ), msg );
310                 usage->num = INITED_VALUE;
311         } else {
312                 unsigned char *dummy = malloc( 1 );
313                 assert( dummy != NULL );
314                 *dummy = INITED_BYTE_VALUE;
315                 if( wraptype == Wrap_scramble ) {
316                         usage->num = ~(LDAP_UINTPTR_T) dummy;
317                         /* Check that ptr<->integer casts work on this host */
318                         assert( (unsigned char *)~usage->num == dummy );
319                 } else {
320                         usage->ptr = dummy + wrap_offset;
321                 }
322         }
323 }
324
325 static void
326 check_usage( ldap_debug_usage_info_t *usage, const char *msg )
327 {
328         if( wraptype == Wrap_noalloc ) {
329                 ERROR_IF( usage->num != INITED_VALUE, msg );
330         } else if( wraptype == Wrap_scramble ) {
331                 ERROR_IF( !usage->num, msg );
332                 ERROR_IF( *(unsigned char *)~usage->num != INITED_BYTE_VALUE, msg );
333         } else {
334                 ERROR_IF( !usage->ptr, msg );
335                 ERROR_IF( usage->ptr[unwrap_offset] != INITED_BYTE_VALUE, msg );
336         }
337 }
338
339 static void
340 free_usage( ldap_debug_usage_info_t *usage, const char *msg )
341 {
342         if( wraptype == Wrap_noalloc ) {
343                 usage->num = ~(LDAP_UINTPTR_T)INITED_VALUE;
344         } else {
345                 unsigned char *dummy = (wraptype == Wrap_scramble
346                                         ? (unsigned char *)~usage->num
347                                         : usage->ptr + unwrap_offset);
348                 *(volatile unsigned char *)dummy = (unsigned char)-1;
349                 free( dummy );
350         }
351 }
352
353 #define with_threads_lock(statement) { \
354         if( !nodebug ) { \
355                 int rc_wtl_ = ldap_int_thread_mutex_lock( &thread_info_mutex ); \
356                 assert( rc_wtl_ == 0 ); \
357         } \
358     statement; \
359         if( !nodebug ) { \
360                 int rc_wtl_ = ldap_int_thread_mutex_unlock( &thread_info_mutex ); \
361                 assert( rc_wtl_ == 0 ); \
362         } \
363 }
364
365 static ldap_debug_thread_t *
366 get_new_thread_info( const char *msg )
367 {
368         if( nodebug )
369                 return NULL;
370         if( thread_info_used >= thread_info_size ) {
371                 unsigned int more = thread_info_size + 1; /* debug value. increase. */
372                 unsigned int new_size = thread_info_size + more;
373                 ldap_debug_thread_t *t = calloc( more, sizeof(ldap_debug_thread_t) );
374                 assert( t != NULL );
375                 t->freeme = 1;
376                 thread_info = realloc( thread_info, new_size * sizeof(*thread_info) );
377                 assert( thread_info != NULL );
378                 while( thread_info_size < new_size ) {
379                         t->idx = thread_info_size;
380                         thread_info[thread_info_size++] = t++;
381                 }
382         }
383         alloc_usage( &thread_info[thread_info_used]->usage, msg );
384         return thread_info[thread_info_used++];
385 }
386
387 static void
388 update_thread_info(
389         ldap_debug_thread_t *t,
390         const ldap_pvt_thread_t *thread,
391         int detached )
392 {
393         if( !nodebug ) {
394                 t->wrapped = *thread;
395                 t->detached = detached;
396         }
397 }
398
399 static void
400 remove_thread_info( ldap_debug_thread_t *t, const char *msg )
401 {
402         if( !nodebug ) {
403                 ldap_debug_thread_t *last;
404                 int idx;
405                 free_usage( &t->usage, msg );
406                 idx = t->idx;
407                 assert( thread_info[idx] == t );
408                 last = thread_info[--thread_info_used];
409                 assert( last->idx == thread_info_used );
410                 (thread_info[idx]              = last)->idx = idx;
411                 (thread_info[thread_info_used] = t   )->idx = thread_info_used;
412         }
413 }
414
415 static ldap_debug_thread_t *
416 get_thread_info( ldap_pvt_thread_t thread, const char *msg )
417 {
418         unsigned int i;
419         ldap_debug_thread_t *t;
420         if( nodebug )
421                 return NULL;
422         for( i = 0; i < thread_info_used; i++ ) {
423                 if( ldap_pvt_thread_equal( thread, thread_info[i]->wrapped ) )
424                         break;
425         }
426         ERROR_IF( i == thread_info_used, msg );
427         t = thread_info[i];
428         check_usage( &t->usage, msg );
429         return t;
430 }
431
432 static void
433 exiting_thread( const char *msg )
434 {
435         if( !nodebug ) {
436                 ldap_pvt_thread_t thread;
437                 thread = ldap_pvt_thread_self();
438                 exit_thread_message( thread );
439                 with_threads_lock({
440                         ldap_debug_thread_t *t = get_thread_info( thread, msg );
441                         if( t->detached )
442                                 remove_thread_info( t, msg );
443                 });
444         }
445 }
446
447 #endif /* LDAP_THREAD_DEBUG_WRAP */
448
449
450 static void
451 adjust_count( int which, int adjust )
452 {
453         int rc;
454         switch( count ) {
455         case Count_no:
456                 break;
457         case Count_yes:
458                 rc = ldap_int_thread_mutex_lock( &resource_mutexes[which] );
459                 assert( rc == 0 );
460                 resource_counts[which] += adjust;
461                 rc = ldap_int_thread_mutex_unlock( &resource_mutexes[which] );
462                 assert( rc == 0 );
463                 break;
464         case Count_reported:
465                 fputs( "...more ldap_debug_thread activity after exit...\n", stderr );
466                 count = Count_reported_more;
467                 /* FALL THROUGH */
468         case Count_reported_more:
469                 /* Not used, but result might be inspected with debugger */
470                 /* (Hopefully threading is disabled by now...) */
471                 resource_counts[which] += adjust;
472                 break;
473         }
474 }
475
476
477 /* Wrappers for LDAP_THREAD_IMPLEMENTATION: */
478
479 /* Used instead of ldap_int_thread_initialize by ldap_pvt_thread_initialize */
480 int
481 ldap_debug_thread_initialize( void )
482 {
483         int i, rc, rc2;
484         if( !options_done )
485                 get_options();
486         ERROR_IF( threading_enabled, "ldap_debug_thread_initialize" );
487         threading_enabled = 1;
488         rc = ldap_int_thread_initialize();
489         if( rc ) {
490                 ERROR( rc, "ldap_debug_thread_initialize:threads" );
491                 threading_enabled = 0;
492         } else {
493                 rc2 = ldap_int_thread_mutex_init( &thread_info_mutex );
494                 assert( rc2 == 0 );
495                 if( count != Count_no ) {
496                         for( i = rc2 = 0; i < Idx_max; i++ )
497                                 rc2 |= ldap_int_thread_mutex_init( &resource_mutexes[i] );
498                         assert( rc2 == 0 );
499                         /* FIXME: Only for static libldap_r as in init.c? If so, why? */
500                         atexit( count_resource_leaks );
501                 }
502         }
503         return rc;
504 }
505
506 /* Used instead of ldap_int_thread_destroy by ldap_pvt_thread_destroy */
507 int
508 ldap_debug_thread_destroy( void )
509 {
510         int rc;
511         ERROR_IF( !threading_enabled, "ldap_debug_thread_destroy" );
512         /* sleep(1) -- need to wait for thread pool to finish? */
513         rc = ldap_int_thread_destroy();
514         if( rc ) {
515                 ERROR( rc, "ldap_debug_thread_destroy:threads" );
516         } else {
517                 threading_enabled = 0;
518         }
519         return rc;
520 }
521
522 int
523 ldap_pvt_thread_set_concurrency( int n )
524 {
525         int rc;
526         ERROR_IF( !threading_enabled, "ldap_pvt_thread_set_concurrency" );
527         rc = ldap_int_thread_set_concurrency( n );
528         ERROR_IF( rc, "ldap_pvt_thread_set_concurrency" );
529         return rc;
530 }
531
532 int
533 ldap_pvt_thread_get_concurrency( void )
534 {
535         int rc;
536         ERROR_IF( !threading_enabled, "ldap_pvt_thread_get_concurrency" );
537         rc = ldap_int_thread_get_concurrency();
538         ERROR_IF( rc, "ldap_pvt_thread_get_concurrency" );
539         return rc;
540 }
541
542 unsigned int
543 ldap_pvt_thread_sleep( unsigned int interval )
544 {
545         int rc;
546         ERROR_IF( !threading_enabled, "ldap_pvt_thread_sleep" );
547         rc = ldap_int_thread_sleep( interval );
548         ERROR_IF( rc, "ldap_pvt_thread_sleep" );
549         return 0;
550 }
551
552 int
553 ldap_pvt_thread_create(
554         ldap_pvt_thread_t *thread,
555         int detach,
556         void *(*start_routine)( void * ),
557         void *arg )
558 {
559         int rc;
560         ERROR_IF( !threading_enabled, "ldap_pvt_thread_create" );
561         if( !options_done )
562                 get_options();
563         with_threads_lock({
564                 ldap_debug_thread_t *t;
565                 t = get_new_thread_info( "ldap_pvt_thread_create" );
566                 rc = ldap_int_thread_create( thread, detach, start_routine, arg );
567                 if( rc ) {
568                         ERROR( rc, "ldap_pvt_thread_create" );
569                         remove_thread_info( t, "ldap_pvt_thread_init" );
570                 } else {
571                         update_thread_info( t, thread, detach );
572                 }
573         });
574         if( rc == 0 ) {
575                 if( tracethreads ) {
576                         char buf[40];
577                         fprintf( stderr, "== Created thread %s%s ==\n",
578                                 thread_name( buf, sizeof(buf), *thread ),
579                                 detach ? " (detached)" : "" );
580                 }
581                 adjust_count( Idx_unexited_thread, +1 );
582                 if( !detach )
583                         adjust_count( Idx_unjoined_thread, +1 );
584         }
585         return rc;
586 }
587
588 void
589 ldap_pvt_thread_exit( void *retval )
590 {
591 #if 0 /* Detached threads may exit after ldap_debug_thread_destroy(). */
592         ERROR_IF( !threading_enabled, "ldap_pvt_thread_exit" );
593 #endif
594         adjust_count( Idx_unexited_thread, -1 );
595         exiting_thread( "ldap_pvt_thread_exit" );
596         ldap_int_thread_exit( retval );
597 }
598
599 int
600 ldap_pvt_thread_join( ldap_pvt_thread_t thread, void **thread_return )
601 {
602         int rc;
603         ldap_debug_thread_t *t;
604         ERROR_IF( !threading_enabled, "ldap_pvt_thread_join" );
605         if( tracethreads ) {
606                 char buf[40];
607                 fprintf( stderr, "== Joining thread %s ==\n",
608                         thread_name( buf, sizeof(buf), thread ) );
609         }
610         with_threads_lock(
611                 t = get_thread_info( thread, "ldap_pvt_thread_join" ) );
612         rc = ldap_int_thread_join( thread, thread_return );
613         if( rc ) {
614                 ERROR( rc, "ldap_pvt_thread_join" );
615         } else {
616                 with_threads_lock(
617                         remove_thread_info( t, "ldap_pvt_thread_join" ) );
618                 adjust_count( Idx_unjoined_thread, -1 );
619         }
620         return rc;
621 }
622
623 int
624 ldap_pvt_thread_kill( ldap_pvt_thread_t thread, int signo )
625 {
626         int rc;
627         ERROR_IF( !threading_enabled, "ldap_pvt_thread_kill" );
628         if( tracethreads ) {
629                 char buf[40];
630                 fprintf( stderr, "== Killing thread %s (sig %i) ==\n",
631                         thread_name( buf, sizeof(buf), thread ), signo );
632         }
633         rc = ldap_int_thread_kill( thread, signo );
634         ERROR_IF( rc, "ldap_pvt_thread_kill" );
635         return rc;
636 }
637
638 int
639 ldap_pvt_thread_yield( void )
640 {
641         int rc;
642         ERROR_IF( !threading_enabled, "ldap_pvt_thread_yield" );
643         rc = ldap_int_thread_yield();
644         ERROR_IF( rc, "ldap_pvt_thread_yield" );
645         return rc;
646 }
647
648 ldap_pvt_thread_t
649 ldap_pvt_thread_self( void )
650 {
651 #if 0 /* Function is used by ch_free() via slap_sl_contxt() in slapd */
652         ERROR_IF( !threading_enabled, "ldap_pvt_thread_self" );
653 #endif
654         return ldap_int_thread_self();
655 }
656
657 int
658 ldap_pvt_thread_cond_init( ldap_pvt_thread_cond_t *cond )
659 {
660         int rc;
661         alloc_usage( &cond->usage, "ldap_pvt_thread_cond_init" );
662         rc = ldap_int_thread_cond_init( WRAPPED( cond ) );
663         if( rc ) {
664                 ERROR( rc, "ldap_pvt_thread_cond_init" );
665                 free_usage( &cond->usage, "ldap_pvt_thread_cond_init" );
666         } else {
667                 adjust_count( Idx_cond, +1 );
668         }
669         return rc;
670 }
671
672 int
673 ldap_pvt_thread_cond_destroy( ldap_pvt_thread_cond_t *cond )
674 {
675         int rc;
676         check_usage( &cond->usage, "ldap_pvt_thread_cond_destroy" );
677         rc = ldap_int_thread_cond_destroy( WRAPPED( cond ) );
678         if( rc ) {
679                 ERROR( rc, "ldap_pvt_thread_cond_destroy" );
680         } else {
681                 free_usage( &cond->usage, "ldap_pvt_thread_cond_destroy" );
682                 adjust_count( Idx_cond, -1 );
683         }
684         return rc;
685 }
686
687 int
688 ldap_pvt_thread_cond_signal( ldap_pvt_thread_cond_t *cond )
689 {
690         int rc;
691         check_usage( &cond->usage, "ldap_pvt_thread_cond_signal" );
692         rc = ldap_int_thread_cond_signal( WRAPPED( cond ) );
693         ERROR_IF( rc, "ldap_pvt_thread_cond_signal" );
694         return rc;
695 }
696
697 int
698 ldap_pvt_thread_cond_broadcast( ldap_pvt_thread_cond_t *cond )
699 {
700         int rc;
701         check_usage( &cond->usage, "ldap_pvt_thread_cond_broadcast" );
702         rc = ldap_int_thread_cond_broadcast( WRAPPED( cond ) );
703         ERROR_IF( rc, "ldap_pvt_thread_cond_broadcast" );
704         return rc;
705 }
706
707 int
708 ldap_pvt_thread_cond_wait(
709         ldap_pvt_thread_cond_t *cond,
710         ldap_pvt_thread_mutex_t *mutex )
711 {
712         int rc;
713         check_usage( &cond->usage, "ldap_pvt_thread_cond_wait:cond" );
714         check_usage( &mutex->usage, "ldap_pvt_thread_cond_wait:mutex" );
715         adjust_count( Idx_locked_mutex, -1 );
716         rc = ldap_int_thread_cond_wait( WRAPPED( cond ), WRAPPED( mutex ) );
717         adjust_count( Idx_locked_mutex, +1 );
718         ERROR_IF( rc, "ldap_pvt_thread_cond_wait" );
719         return rc;
720 }
721
722 int
723 ldap_pvt_thread_mutex_init( ldap_pvt_thread_mutex_t *mutex )
724 {
725         int rc;
726         alloc_usage( &mutex->usage, "ldap_pvt_thread_mutex_init" );
727         rc = ldap_int_thread_mutex_init( WRAPPED( mutex ) );
728         if( rc ) {
729                 ERROR( rc, "ldap_pvt_thread_mutex_init" );
730                 free_usage( &mutex->usage, "ldap_pvt_thread_mutex_init" );
731         } else {
732                 adjust_count( Idx_mutex, +1 );
733         }
734         return rc;
735 }
736
737 int
738 ldap_pvt_thread_mutex_destroy( ldap_pvt_thread_mutex_t *mutex )
739 {
740         int rc;
741         check_usage( &mutex->usage, "ldap_pvt_thread_mutex_destroy" );
742         rc = ldap_int_thread_mutex_destroy( WRAPPED( mutex ) );
743         if( rc ) {
744                 ERROR( rc, "ldap_pvt_thread_mutex_destroy" );
745         } else {
746                 free_usage( &mutex->usage, "ldap_pvt_thread_mutex_destroy" );
747                 adjust_count( Idx_mutex, -1 );
748         }
749         return rc;
750 }
751
752 int
753 ldap_pvt_thread_mutex_lock( ldap_pvt_thread_mutex_t *mutex )
754 {
755         int rc;
756         check_usage( &mutex->usage, "ldap_pvt_thread_mutex_lock" );
757         rc = ldap_int_thread_mutex_lock( WRAPPED( mutex ) );
758         if( rc ) {
759                 ERROR_IF( rc, "ldap_pvt_thread_mutex_lock" );
760         } else {
761                 adjust_count( Idx_locked_mutex, +1 );
762         }
763         return rc;
764 }
765
766 int
767 ldap_pvt_thread_mutex_trylock( ldap_pvt_thread_mutex_t *mutex )
768 {
769         int rc;
770         check_usage( &mutex->usage, "ldap_pvt_thread_mutex_trylock" );
771         rc = ldap_int_thread_mutex_trylock( WRAPPED( mutex ) );
772         if( rc == 0 )
773                 adjust_count( Idx_locked_mutex, +1 );
774         return rc;
775 }
776
777 int
778 ldap_pvt_thread_mutex_unlock( ldap_pvt_thread_mutex_t *mutex )
779 {
780         int rc;
781         check_usage( &mutex->usage, "ldap_pvt_thread_mutex_unlock" );
782         rc = ldap_int_thread_mutex_unlock( WRAPPED( mutex ) );
783         if( rc ) {
784                 ERROR_IF( rc, "ldap_pvt_thread_mutex_unlock" );
785         } else {
786                 adjust_count( Idx_locked_mutex, -1 );
787         }
788         return rc;
789 }
790
791
792 /* Wrappers for LDAP_THREAD_RDWR_IMPLEMENTATION: */
793
794 int
795 ldap_pvt_thread_rdwr_init( ldap_pvt_thread_rdwr_t *rwlock )
796 {
797         int rc;
798         alloc_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_init" );
799         rc = ldap_int_thread_rdwr_init( WRAPPED( rwlock ) );
800         if( rc ) {
801                 ERROR( rc, "ldap_pvt_thread_rdwr_init" );
802                 free_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_init" );
803         } else {
804                 adjust_count( Idx_rdwr, +1 );
805         }
806         return rc;
807 }
808
809 int
810 ldap_pvt_thread_rdwr_destroy( ldap_pvt_thread_rdwr_t *rwlock )
811 {
812         int rc;
813         check_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_destroy" );
814         rc = ldap_int_thread_rdwr_destroy( WRAPPED( rwlock ) );
815         if( rc ) {
816                 ERROR( rc, "ldap_pvt_thread_rdwr_destroy" );
817         } else {
818                 free_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_destroy" );
819                 adjust_count( Idx_rdwr, -1 );
820         }
821         return rc;
822 }
823
824 int
825 ldap_pvt_thread_rdwr_rlock( ldap_pvt_thread_rdwr_t *rwlock )
826 {
827         int rc;
828         check_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_rlock" );
829         rc = ldap_int_thread_rdwr_rlock( WRAPPED( rwlock ) );
830         ERROR_IF( rc, "ldap_pvt_thread_rdwr_rlock" );
831         return rc;
832 }
833
834 int
835 ldap_pvt_thread_rdwr_rtrylock( ldap_pvt_thread_rdwr_t *rwlock )
836 {
837         check_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_rtrylock" );
838         return ldap_int_thread_rdwr_rtrylock( WRAPPED( rwlock ) );
839 }
840
841 int
842 ldap_pvt_thread_rdwr_runlock( ldap_pvt_thread_rdwr_t *rwlock )
843 {
844         int rc;
845         check_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_runlock" );
846         rc = ldap_int_thread_rdwr_runlock( WRAPPED( rwlock ) );
847         ERROR_IF( rc, "ldap_pvt_thread_rdwr_runlock" );
848         return rc;
849 }
850
851 int
852 ldap_pvt_thread_rdwr_wlock( ldap_pvt_thread_rdwr_t *rwlock )
853 {
854         int rc;
855         check_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_wlock" );
856         rc = ldap_int_thread_rdwr_wlock( WRAPPED( rwlock ) );
857         ERROR_IF( rc, "ldap_pvt_thread_rdwr_wlock" );
858         return rc;
859 }
860
861 int
862 ldap_pvt_thread_rdwr_wtrylock( ldap_pvt_thread_rdwr_t *rwlock )
863 {
864         check_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_wtrylock" );
865         return ldap_int_thread_rdwr_wtrylock( WRAPPED( rwlock ) );
866 }
867
868 int
869 ldap_pvt_thread_rdwr_wunlock( ldap_pvt_thread_rdwr_t *rwlock )
870 {
871         int rc;
872         check_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_wunlock" );
873         rc = ldap_int_thread_rdwr_wunlock( WRAPPED( rwlock ) );
874         ERROR_IF( rc, "ldap_pvt_thread_rdwr_wunlock" );
875         return rc;
876 }
877
878 #ifdef LDAP_RDWR_DEBUG
879
880 int
881 ldap_pvt_thread_rdwr_readers( ldap_pvt_thread_rdwr_t *rwlock )
882 {
883         check_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_readers" );
884         return ldap_int_thread_rdwr_readers( WRAPPED( rwlock ) );
885 }
886
887 int
888 ldap_pvt_thread_rdwr_writers( ldap_pvt_thread_rdwr_t *rwlock )
889 {
890         check_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_writers" );
891         return ldap_int_thread_rdwr_writers( WRAPPED( rwlock ) );
892 }
893
894 int
895 ldap_pvt_thread_rdwr_active( ldap_pvt_thread_rdwr_t *rwlock )
896 {
897         check_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_active" );
898         return ldap_int_thread_rdwr_active( WRAPPED( rwlock ) );
899 }
900
901 #endif /* LDAP_RDWR_DEBUG */
902
903
904 /* Some wrappers for LDAP_THREAD_POOL_IMPLEMENTATION: */
905 #ifdef LDAP_THREAD_POOL_IMPLEMENTATION
906
907 int
908 ldap_pvt_thread_pool_init(
909         ldap_pvt_thread_pool_t *tpool,
910         int max_threads,
911         int max_pending )
912 {
913         int rc;
914         ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_init" );
915         rc = ldap_int_thread_pool_init( tpool, max_threads, max_pending );
916         if( rc ) {
917                 ERROR( rc, "ldap_pvt_thread_pool_init" );
918         } else {
919                 adjust_count( Idx_tpool, +1 );
920         }
921         return rc;
922 }
923
924 int
925 ldap_pvt_thread_pool_submit(
926         ldap_pvt_thread_pool_t *tpool,
927         ldap_pvt_thread_start_t *start_routine, void *arg )
928 {
929         int rc, has_pool;
930         ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_submit" );
931         has_pool = (tpool && *tpool);
932         rc = ldap_int_thread_pool_submit( tpool, start_routine, arg );
933         if( has_pool )
934                 ERROR_IF( rc, "ldap_pvt_thread_pool_submit" );
935         return rc;
936 }
937
938 int
939 ldap_pvt_thread_pool_maxthreads(
940         ldap_pvt_thread_pool_t *tpool,
941         int max_threads )
942 {
943         ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_maxthreads" );
944         return ldap_int_thread_pool_maxthreads( tpool, max_threads );
945 }
946
947 int
948 ldap_pvt_thread_pool_backload( ldap_pvt_thread_pool_t *tpool )
949 {
950         ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_backload" );
951         return ldap_int_thread_pool_backload( tpool );
952 }
953
954 int
955 ldap_pvt_thread_pool_destroy( ldap_pvt_thread_pool_t *tpool, int run_pending )
956 {
957         int rc, has_pool;
958         ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_destroy" );
959         has_pool = (tpool && *tpool);
960         rc = ldap_int_thread_pool_destroy( tpool, run_pending );
961         if( has_pool ) {
962                 if( rc ) {
963                         ERROR( rc, "ldap_pvt_thread_pool_destroy" );
964                 } else {
965                         adjust_count( Idx_tpool, -1 );
966                 }
967         }
968         return rc;
969 }
970
971 int
972 ldap_pvt_thread_pool_pause( ldap_pvt_thread_pool_t *tpool )
973 {
974         ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_pause" );
975         return ldap_int_thread_pool_pause( tpool );
976 }
977
978 int
979 ldap_pvt_thread_pool_resume( ldap_pvt_thread_pool_t *tpool )
980 {
981         ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_resume" );
982         return ldap_int_thread_pool_resume( tpool );
983 }
984
985 int
986 ldap_pvt_thread_pool_getkey(
987         void *xctx,
988         void *key,
989         void **data,
990         ldap_pvt_thread_pool_keyfree_t **kfree )
991 {
992 #if 0 /* Function is used by ch_free() via slap_sl_contxt() in slapd */
993         ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_getkey" );
994 #endif
995         return ldap_int_thread_pool_getkey( xctx, key, data, kfree );
996 }
997
998 int
999 ldap_pvt_thread_pool_setkey(
1000         void *xctx,
1001         void *key,
1002         void *data,
1003         ldap_pvt_thread_pool_keyfree_t *kfree )
1004 {
1005         int rc;
1006         ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_setkey" );
1007         rc = ldap_int_thread_pool_setkey( xctx, key, data, kfree );
1008         ERROR_IF( rc, "ldap_pvt_thread_pool_setkey" );
1009         return rc;
1010 }
1011
1012 void
1013 ldap_pvt_thread_pool_purgekey( void *key )
1014 {
1015         ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_purgekey" );
1016         ldap_int_thread_pool_purgekey( key );
1017 }
1018
1019 void *
1020 ldap_pvt_thread_pool_context( void )
1021 {
1022 #if 0 /* Function is used by ch_free() via slap_sl_contxt() in slapd */
1023         ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_context" );
1024 #endif
1025         return ldap_int_thread_pool_context();
1026 }
1027
1028 void
1029 ldap_pvt_thread_pool_context_reset( void *vctx )
1030 {
1031         ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_context_reset" );
1032         ldap_int_thread_pool_context_reset( vctx );
1033 }
1034
1035 #endif /* LDAP_THREAD_POOL_IMPLEMENTATION */
1036
1037 #endif /* LDAP_THREAD_DEBUG */