]> git.sur5r.net Git - openldap/blob - libraries/libldap_r/thr_debug.c
Happy new year!
[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-2006 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;
209                         for( oi = option_info; oi->name; oi++ ) {
210                                 if( strncasecmp( oi->name, s, optlen ) == 0 ) {
211                                         if( oi->name && oi->name[optlen] == '\0' ) {
212                                                 *oi->var = oi->val;
213                                         } else {
214                                                 fprintf( stderr, "Unknown $%s option '%.*s'\n",
215                                                         "LDAP_THREAD_DEBUG", (int) optlen, s );
216                                         }
217                                         break;
218                                 }
219                         }
220                         s += optlen;
221                 }
222         }
223         if( nodebug ) {
224                 noabort = noerror = 1;
225                 tracethreads = dupinit = 0;
226                 count = Count_no;
227         }
228 #ifdef LDAP_THREAD_DEBUG_WRAP
229         if( nodebug || dupinit ) {
230                 wraptype = Wrap_noalloc;
231         } else if( wraptype == Wrap_scramble ) {
232                 const unsigned char *dummy = (const unsigned char *)&option_info;
233                 if( sizeof(LDAP_UINTPTR_T) < sizeof(void *)
234                         || (unsigned char *)~~(LDAP_UINTPTR_T) dummy != dummy
235                         || (unsigned char *)~~(LDAP_UINTPTR_T) (unsigned char *)0 )
236                 {
237                         fprintf( stderr, "Misconfigured for $%s %s.  Using %s.\n",
238                                 "LDAP_THREAD_DEBUG", "scramble", "adjptr" );
239                         wraptype = Wrap_adjptr;
240                 }
241         }
242         unwrap_offset = -(wrap_offset = (wraptype == Wrap_adjptr));
243 #endif
244         options_done = 1;
245 }
246
247
248 static char *
249 thread_name( char *buf, int bufsize, ldap_pvt_thread_t thread )
250 {
251         int i;
252         --bufsize;
253         if( bufsize > 2*sizeof(thread) )
254                 bufsize = 2*sizeof(thread);
255         for( i = 0; i < bufsize; i += 2 )
256                 snprintf( buf+i, 3, "%02x", ((unsigned char *)&thread)[i/2] );
257         return buf;
258 }
259
260 static void
261 exit_thread_message( const ldap_pvt_thread_t thread )
262 {
263         if( tracethreads ) {
264                 char buf[40];
265                 fprintf( stderr, "== Exiting thread %s ==\n",
266                         thread_name( buf, sizeof(buf), thread ) );
267         }
268 }
269
270
271 #ifndef LDAP_THREAD_DEBUG_WRAP
272
273 #define WRAPPED(ptr)                    (ptr)
274 #define alloc_usage(ptr, msg)   ((void) 0)
275 #define check_usage(ptr, msg)   ((void) 0)
276 #define free_usage(ptr, msg)    ((void) 0)
277
278 #define with_threads_lock(statement)    { statement; }
279 #define get_new_thread_info(msg)                NULL
280 #define update_thread_info(ti, th, det) {}
281 #define remove_thread_info(ti, msg)             ((void)0)
282 #define get_thread_info(thread, msg)    NULL
283 #define exiting_thread(msg)     exit_thread_message(ldap_pvt_thread_self())
284
285 #else /* LDAP_THREAD_DEBUG_WRAP */
286
287 #define WRAPPED(ptr)                    (&(ptr)->wrapped)
288
289 #define INITED_VALUE            0x12345678UL
290 #define INITED_BYTE_VALUE       0xd5
291
292 static int
293 debug_already_initialized( const LDAP_UINTPTR_T *num )
294 {
295         /* Valid programs will access uninitialized memory if dupinit */
296         return dupinit && *num == INITED_VALUE;
297 }
298
299 static void
300 alloc_usage( ldap_debug_usage_info_t *usage, const char *msg )
301 {
302         if( !options_done )
303                 get_options();
304         if( wraptype == Wrap_noalloc ) {
305                 ERROR_IF( debug_already_initialized( &usage->num ), msg );
306                 usage->num = INITED_VALUE;
307         } else {
308                 unsigned char *dummy = malloc( 1 );
309                 assert( dummy != NULL );
310                 *dummy = INITED_BYTE_VALUE;
311                 if( wraptype == Wrap_scramble ) {
312                         usage->num = ~(LDAP_UINTPTR_T) dummy;
313                         assert( (unsigned char *)~usage->num == dummy );
314                 } else {
315                         usage->ptr = dummy + wrap_offset;
316                 }
317         }
318 }
319
320 static void
321 check_usage( ldap_debug_usage_info_t *usage, const char *msg )
322 {
323         if( wraptype == Wrap_noalloc ) {
324                 ERROR_IF( usage->num != INITED_VALUE, msg );
325         } else if( wraptype == Wrap_scramble ) {
326                 ERROR_IF( !usage->num, msg );
327                 ERROR_IF( *(unsigned char *)~usage->num != INITED_BYTE_VALUE, msg );
328         } else {
329                 ERROR_IF( !usage->ptr, msg );
330                 ERROR_IF( usage->ptr[unwrap_offset] != INITED_BYTE_VALUE, msg );
331         }
332 }
333
334 static void
335 free_usage( ldap_debug_usage_info_t *usage, const char *msg )
336 {
337         if( wraptype == Wrap_noalloc ) {
338                 usage->num = ~(LDAP_UINTPTR_T)INITED_VALUE;
339         } else {
340                 unsigned char *dummy = (wraptype == Wrap_scramble
341                                         ? (unsigned char *)~usage->num
342                                         : usage->ptr + unwrap_offset);
343                 *(volatile unsigned char *)dummy = (unsigned char)-1;
344                 free( dummy );
345         }
346 }
347
348 #define with_threads_lock(statement) { \
349         if( !nodebug ) { \
350                 int rc_wtl_ = ldap_int_thread_mutex_lock( &thread_info_mutex ); \
351                 assert( rc_wtl_ == 0 ); \
352         } \
353     statement; \
354         if( !nodebug ) { \
355                 int rc_wtl_ = ldap_int_thread_mutex_unlock( &thread_info_mutex ); \
356                 assert( rc_wtl_ == 0 ); \
357         } \
358 }
359
360 static ldap_debug_thread_t *
361 get_new_thread_info( const char *msg )
362 {
363         if( nodebug )
364                 return NULL;
365         if( thread_info_used >= thread_info_size ) {
366                 unsigned int more = thread_info_size + 1; /* debug value. increase. */
367                 unsigned int new_size = thread_info_size + more;
368                 ldap_debug_thread_t *t = calloc( more, sizeof(ldap_debug_thread_t) );
369                 assert( t != NULL );
370                 t->freeme = 1;
371                 thread_info = realloc( thread_info, new_size * sizeof(*thread_info) );
372                 assert( thread_info != NULL );
373                 while( thread_info_size < new_size ) {
374                         t->idx = thread_info_size;
375                         thread_info[thread_info_size++] = t++;
376                 }
377         }
378         alloc_usage( &thread_info[thread_info_used]->usage, msg );
379         return thread_info[thread_info_used++];
380 }
381
382 static void
383 update_thread_info(
384         ldap_debug_thread_t *t,
385         const ldap_pvt_thread_t *thread,
386         int detached )
387 {
388         if( !nodebug ) {
389                 t->wrapped = *thread;
390                 t->detached = detached;
391         }
392 }
393
394 static void
395 remove_thread_info( ldap_debug_thread_t *t, const char *msg )
396 {
397         if( !nodebug ) {
398                 ldap_debug_thread_t *last;
399                 int idx;
400                 free_usage( &t->usage, msg );
401                 idx = t->idx;
402                 assert( thread_info[idx] == t );
403                 last = thread_info[--thread_info_used];
404                 assert( last->idx == thread_info_used );
405                 (thread_info[idx]              = last)->idx = idx;
406                 (thread_info[thread_info_used] = t   )->idx = thread_info_used;
407         }
408 }
409
410 ldap_debug_thread_t *
411 get_thread_info( ldap_pvt_thread_t *thread, const char *msg )
412 {
413         unsigned int i;
414         ldap_debug_thread_t *t;
415         if( nodebug )
416                 return NULL;
417         for( i = 0; i < thread_info_used; i++ ) {
418                 if( ldap_pvt_thread_equal( *thread, thread_info[i]->wrapped ) )
419                         break;
420         }
421         ERROR_IF( i == thread_info_used, msg );
422         t = thread_info[i];
423         check_usage( &t->usage, msg );
424         return t;
425 }
426
427 static void
428 exiting_thread( const char *msg )
429 {
430         if( !nodebug ) {
431                 ldap_pvt_thread_t thread;
432                 thread = ldap_pvt_thread_self();
433                 exit_thread_message( thread );
434                 with_threads_lock({
435                         ldap_debug_thread_t *t = get_thread_info( &thread, msg );
436                         if( t->detached )
437                                 remove_thread_info( t, msg );
438                 });
439         }
440 }
441
442 #endif /* LDAP_THREAD_DEBUG_WRAP */
443
444
445 static void
446 adjust_count( int which, int adjust )
447 {
448         int rc;
449         switch( count ) {
450         case Count_no:
451                 break;
452         case Count_yes:
453                 rc = ldap_int_thread_mutex_lock( &resource_mutexes[which] );
454                 assert( rc == 0 );
455                 resource_counts[which] += adjust;
456                 rc = ldap_int_thread_mutex_unlock( &resource_mutexes[which] );
457                 assert( rc == 0 );
458         case Count_reported:
459                 fputs( "...more ldap_debug_thread activity after exit...\n", stderr );
460                 count = Count_reported_more;
461                 /* FALL THROUGH */
462         case Count_reported_more:
463                 /* Not used, but result might be inspected with debugger */
464                 /* (Hopefully threading is disabled by now...) */
465                 resource_counts[which] += adjust;
466                 break;
467         }
468 }
469
470
471 /* Wrappers for LDAP_THREAD_IMPLEMENTATION: */
472
473 /* Used instead of ldap_int_thread_initialize by ldap_pvt_thread_initialize */
474 int
475 ldap_debug_thread_initialize( void )
476 {
477         int i, rc, rc2;
478         if( !options_done )
479                 get_options();
480         ERROR_IF( threading_enabled, "ldap_debug_thread_initialize" );
481         threading_enabled = 1;
482         rc = ldap_int_thread_initialize();
483         if( rc ) {
484                 ERROR( rc, "ldap_debug_thread_initialize:threads" );
485                 threading_enabled = 0;
486         } else {
487                 rc2 = ldap_int_thread_mutex_init( &thread_info_mutex );
488                 assert( rc2 == 0 );
489                 if( count != Count_no ) {
490                         for( i = rc2 = 0; i < Idx_max; i++ )
491                                 rc2 |= ldap_int_thread_mutex_init( &resource_mutexes[i] );
492                         assert( rc2 == 0 );
493                         /* FIXME: Only for static libldap_r as in init.c? If so, why? */
494                         atexit( count_resource_leaks );
495                 }
496         }
497         return rc;
498 }
499
500 /* Used instead of ldap_int_thread_destroy by ldap_pvt_thread_destroy */
501 int
502 ldap_debug_thread_destroy( void )
503 {
504         int rc;
505         ERROR_IF( !threading_enabled, "ldap_debug_thread_destroy" );
506         /* sleep(1) -- need to wait for thread pool to finish? */
507         rc = ldap_int_thread_destroy();
508         if( rc ) {
509                 ERROR( rc, "ldap_debug_thread_destroy:threads" );
510         } else {
511                 threading_enabled = 0;
512         }
513         return rc;
514 }
515
516 int
517 ldap_pvt_thread_set_concurrency( int n )
518 {
519         int rc;
520         ERROR_IF( !threading_enabled, "ldap_pvt_thread_set_concurrency" );
521         rc = ldap_int_thread_set_concurrency( n );
522         ERROR_IF( rc, "ldap_pvt_thread_set_concurrency" );
523         return rc;
524 }
525
526 int
527 ldap_pvt_thread_get_concurrency( void )
528 {
529         int rc;
530         ERROR_IF( !threading_enabled, "ldap_pvt_thread_get_concurrency" );
531         rc = ldap_int_thread_get_concurrency();
532         ERROR_IF( rc, "ldap_pvt_thread_get_concurrency" );
533         return rc;
534 }
535
536 unsigned int
537 ldap_pvt_thread_sleep( unsigned int interval )
538 {
539         int rc;
540         ERROR_IF( !threading_enabled, "ldap_pvt_thread_sleep" );
541         rc = ldap_int_thread_sleep( interval );
542         ERROR_IF( rc, "ldap_pvt_thread_sleep" );
543         return 0;
544 }
545
546 int
547 ldap_pvt_thread_create(
548         ldap_pvt_thread_t *thread,
549         int detach,
550         void *(*start_routine)( void * ),
551         void *arg )
552 {
553         int rc;
554         ERROR_IF( !threading_enabled, "ldap_pvt_thread_create" );
555         if( !options_done )
556                 get_options();
557         with_threads_lock({
558                 ldap_debug_thread_t *t;
559                 t = get_new_thread_info( "ldap_pvt_thread_create" );
560                 rc = ldap_int_thread_create( thread, detach, start_routine, arg );
561                 if( rc ) {
562                         ERROR( rc, "ldap_pvt_thread_create" );
563                         remove_thread_info( t, "ldap_pvt_thread_init" );
564                 } else {
565                         update_thread_info( t, thread, detach );
566                 }
567         });
568         if( rc == 0 ) {
569                 if( tracethreads ) {
570                         char buf[40];
571                         fprintf( stderr, "== Created thread %s%s ==\n",
572                                 thread_name( buf, sizeof(buf), *thread ),
573                                 detach ? " (detached)" : "" );
574                 }
575                 adjust_count( Idx_unexited_thread, +1 );
576                 if( !detach )
577                         adjust_count( Idx_unjoined_thread, +1 );
578         }
579         return rc;
580 }
581
582 void
583 ldap_pvt_thread_exit( void *retval )
584 {
585         ERROR_IF( !threading_enabled, "ldap_pvt_thread_exit" );
586         adjust_count( Idx_unexited_thread, -1 );
587         exiting_thread( "ldap_pvt_thread_exit" );
588         ldap_int_thread_exit( retval );
589 }
590
591 int
592 ldap_pvt_thread_join( ldap_pvt_thread_t thread, void **thread_return )
593 {
594         int rc;
595         ldap_debug_thread_t *t;
596         ERROR_IF( !threading_enabled, "ldap_pvt_thread_join" );
597         if( tracethreads ) {
598                 char buf[40];
599                 fprintf( stderr, "== Joining thread %s ==\n",
600                         thread_name( buf, sizeof(buf), thread ) );
601         }
602         with_threads_lock(
603                 t = get_thread_info( &thread, "ldap_pvt_thread_join" ) );
604         rc = ldap_int_thread_join( thread, thread_return );
605         if( rc ) {
606                 ERROR( rc, "ldap_pvt_thread_join" );
607         } else {
608                 with_threads_lock(
609                         remove_thread_info( t, "ldap_pvt_thread_join" ) );
610                 adjust_count( Idx_unjoined_thread, -1 );
611         }
612         return rc;
613 }
614
615 int
616 ldap_pvt_thread_kill( ldap_pvt_thread_t thread, int signo )
617 {
618         int rc;
619         ERROR_IF( !threading_enabled, "ldap_pvt_thread_kill" );
620         if( tracethreads ) {
621                 char buf[40];
622                 fprintf( stderr, "== Killing thread %s (sig %i) ==\n",
623                         thread_name( buf, sizeof(buf), thread ), signo );
624         }
625         rc = ldap_int_thread_kill( thread, signo );
626         ERROR_IF( rc, "ldap_pvt_thread_kill" );
627         return rc;
628 }
629
630 int
631 ldap_pvt_thread_yield( void )
632 {
633         int rc;
634         ERROR_IF( !threading_enabled, "ldap_pvt_thread_yield" );
635         rc = ldap_int_thread_yield();
636         ERROR_IF( rc, "ldap_pvt_thread_yield" );
637         return rc;
638 }
639
640 ldap_pvt_thread_t
641 ldap_pvt_thread_self( void )
642 {
643 #if 0 /* Function is used by ch_free() via slap_sl_contxt() in slapd */
644         ERROR_IF( !threading_enabled, "ldap_pvt_thread_self" );
645 #endif
646         return ldap_int_thread_self();
647 }
648
649 int
650 ldap_pvt_thread_cond_init( ldap_pvt_thread_cond_t *cond )
651 {
652         int rc;
653         alloc_usage( &cond->usage, "ldap_pvt_thread_cond_init" );
654         rc = ldap_int_thread_cond_init( WRAPPED( cond ) );
655         if( rc ) {
656                 ERROR( rc, "ldap_pvt_thread_cond_init" );
657                 free_usage( &cond->usage, "ldap_pvt_thread_cond_init" );
658         } else {
659                 adjust_count( Idx_cond, +1 );
660         }
661         return rc;
662 }
663
664 int
665 ldap_pvt_thread_cond_destroy( ldap_pvt_thread_cond_t *cond )
666 {
667         int rc;
668         check_usage( &cond->usage, "ldap_pvt_thread_cond_destroy" );
669         rc = ldap_int_thread_cond_destroy( WRAPPED( cond ) );
670         if( rc ) {
671                 ERROR( rc, "ldap_pvt_thread_cond_destroy" );
672         } else {
673                 free_usage( &cond->usage, "ldap_pvt_thread_cond_destroy" );
674                 adjust_count( Idx_cond, -1 );
675         }
676         return rc;
677 }
678
679 int
680 ldap_pvt_thread_cond_signal( ldap_pvt_thread_cond_t *cond )
681 {
682         int rc;
683         check_usage( &cond->usage, "ldap_pvt_thread_cond_signal" );
684         rc = ldap_int_thread_cond_signal( WRAPPED( cond ) );
685         ERROR_IF( rc, "ldap_pvt_thread_cond_signal" );
686         return rc;
687 }
688
689 int
690 ldap_pvt_thread_cond_broadcast( ldap_pvt_thread_cond_t *cond )
691 {
692         int rc;
693         check_usage( &cond->usage, "ldap_pvt_thread_cond_broadcast" );
694         rc = ldap_int_thread_cond_broadcast( WRAPPED( cond ) );
695         ERROR_IF( rc, "ldap_pvt_thread_cond_broadcast" );
696         return rc;
697 }
698
699 int
700 ldap_pvt_thread_cond_wait(
701         ldap_pvt_thread_cond_t *cond,
702         ldap_pvt_thread_mutex_t *mutex )
703 {
704         int rc;
705         check_usage( &cond->usage, "ldap_pvt_thread_cond_wait:cond" );
706         check_usage( &mutex->usage, "ldap_pvt_thread_cond_wait:mutex" );
707         adjust_count( Idx_locked_mutex, -1 );
708         rc = ldap_int_thread_cond_wait( WRAPPED( cond ), WRAPPED( mutex ) );
709         adjust_count( Idx_locked_mutex, +1 );
710         ERROR_IF( rc, "ldap_pvt_thread_cond_wait" );
711         return rc;
712 }
713
714 int
715 ldap_pvt_thread_mutex_init( ldap_pvt_thread_mutex_t *mutex )
716 {
717         int rc;
718         alloc_usage( &mutex->usage, "ldap_pvt_thread_mutex_init" );
719         rc = ldap_int_thread_mutex_init( WRAPPED( mutex ) );
720         if( rc ) {
721                 ERROR( rc, "ldap_pvt_thread_mutex_init" );
722                 free_usage( &mutex->usage, "ldap_pvt_thread_mutex_init" );
723         } else {
724                 adjust_count( Idx_mutex, +1 );
725         }
726         return rc;
727 }
728
729 int
730 ldap_pvt_thread_mutex_destroy( ldap_pvt_thread_mutex_t *mutex )
731 {
732         int rc;
733         check_usage( &mutex->usage, "ldap_pvt_thread_mutex_destroy" );
734         rc = ldap_int_thread_mutex_destroy( WRAPPED( mutex ) );
735         if( rc ) {
736                 ERROR( rc, "ldap_pvt_thread_mutex_destroy" );
737         } else {
738                 free_usage( &mutex->usage, "ldap_pvt_thread_mutex_destroy" );
739                 adjust_count( Idx_mutex, -1 );
740         }
741         return rc;
742 }
743
744 int
745 ldap_pvt_thread_mutex_lock( ldap_pvt_thread_mutex_t *mutex )
746 {
747         int rc;
748         check_usage( &mutex->usage, "ldap_pvt_thread_mutex_lock" );
749         rc = ldap_int_thread_mutex_lock( WRAPPED( mutex ) );
750         if( rc ) {
751                 ERROR_IF( rc, "ldap_pvt_thread_mutex_lock" );
752         } else {
753                 adjust_count( Idx_locked_mutex, +1 );
754         }
755         return rc;
756 }
757
758 int
759 ldap_pvt_thread_mutex_trylock( ldap_pvt_thread_mutex_t *mutex )
760 {
761         int rc;
762         check_usage( &mutex->usage, "ldap_pvt_thread_mutex_trylock" );
763         rc = ldap_int_thread_mutex_trylock( WRAPPED( mutex ) );
764         if( rc == 0 )
765                 adjust_count( Idx_locked_mutex, +1 );
766         return rc;
767 }
768
769 int
770 ldap_pvt_thread_mutex_unlock( ldap_pvt_thread_mutex_t *mutex )
771 {
772         int rc;
773         check_usage( &mutex->usage, "ldap_pvt_thread_mutex_unlock" );
774         rc = ldap_int_thread_mutex_unlock( WRAPPED( mutex ) );
775         if( rc ) {
776                 ERROR_IF( rc, "ldap_pvt_thread_mutex_unlock" );
777         } else {
778                 adjust_count( Idx_locked_mutex, -1 );
779         }
780         return rc;
781 }
782
783
784 /* Wrappers for LDAP_THREAD_RDWR_IMPLEMENTATION: */
785
786 int
787 ldap_pvt_thread_rdwr_init( ldap_pvt_thread_rdwr_t *rwlock )
788 {
789         int rc;
790         alloc_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_init" );
791         rc = ldap_int_thread_rdwr_init( WRAPPED( rwlock ) );
792         if( rc ) {
793                 ERROR( rc, "ldap_pvt_thread_rdwr_init" );
794                 free_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_init" );
795         } else {
796                 adjust_count( Idx_rdwr, +1 );
797         }
798         return rc;
799 }
800
801 int
802 ldap_pvt_thread_rdwr_destroy( ldap_pvt_thread_rdwr_t *rwlock )
803 {
804         int rc;
805         check_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_destroy" );
806         rc = ldap_int_thread_rdwr_destroy( WRAPPED( rwlock ) );
807         if( rc ) {
808                 ERROR( rc, "ldap_pvt_thread_rdwr_destroy" );
809         } else {
810                 free_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_destroy" );
811                 adjust_count( Idx_rdwr, -1 );
812         }
813         return rc;
814 }
815
816 int
817 ldap_pvt_thread_rdwr_rlock( ldap_pvt_thread_rdwr_t *rwlock )
818 {
819         int rc;
820         check_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_rlock" );
821         rc = ldap_int_thread_rdwr_rlock( WRAPPED( rwlock ) );
822         ERROR_IF( rc, "ldap_pvt_thread_rdwr_rlock" );
823         return rc;
824 }
825
826 int
827 ldap_pvt_thread_rdwr_rtrylock( ldap_pvt_thread_rdwr_t *rwlock )
828 {
829         check_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_rtrylock" );
830         return ldap_int_thread_rdwr_rtrylock( WRAPPED( rwlock ) );
831 }
832
833 int
834 ldap_pvt_thread_rdwr_runlock( ldap_pvt_thread_rdwr_t *rwlock )
835 {
836         int rc;
837         check_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_runlock" );
838         rc = ldap_int_thread_rdwr_runlock( WRAPPED( rwlock ) );
839         ERROR_IF( rc, "ldap_pvt_thread_rdwr_runlock" );
840         return rc;
841 }
842
843 int
844 ldap_pvt_thread_rdwr_wlock( ldap_pvt_thread_rdwr_t *rwlock )
845 {
846         int rc;
847         check_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_wlock" );
848         rc = ldap_int_thread_rdwr_wlock( WRAPPED( rwlock ) );
849         ERROR_IF( rc, "ldap_pvt_thread_rdwr_wlock" );
850         return rc;
851 }
852
853 int
854 ldap_pvt_thread_rdwr_wtrylock( ldap_pvt_thread_rdwr_t *rwlock )
855 {
856         check_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_wtrylock" );
857         return ldap_int_thread_rdwr_wtrylock( WRAPPED( rwlock ) );
858 }
859
860 int
861 ldap_pvt_thread_rdwr_wunlock( ldap_pvt_thread_rdwr_t *rwlock )
862 {
863         int rc;
864         check_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_wunlock" );
865         rc = ldap_int_thread_rdwr_wunlock( WRAPPED( rwlock ) );
866         ERROR_IF( rc, "ldap_pvt_thread_rdwr_wunlock" );
867         return rc;
868 }
869
870 #ifdef LDAP_RDWR_DEBUG
871
872 int
873 ldap_pvt_thread_rdwr_readers( ldap_pvt_thread_rdwr_t *rwlock )
874 {
875         check_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_readers" );
876         return ldap_int_thread_rdwr_readers( WRAPPED( rwlock ) );
877 }
878
879 int
880 ldap_pvt_thread_rdwr_writers( ldap_pvt_thread_rdwr_t *rwlock )
881 {
882         check_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_writers" );
883         return ldap_int_thread_rdwr_writers( WRAPPED( rwlock ) );
884 }
885
886 int
887 ldap_pvt_thread_rdwr_active( ldap_pvt_thread_rdwr_t *rwlock )
888 {
889         check_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_active" );
890         return ldap_int_thread_rdwr_active( WRAPPED( rwlock ) );
891 }
892
893 #endif /* LDAP_RDWR_DEBUG */
894
895
896 /* Some wrappers for LDAP_THREAD_POOL_IMPLEMENTATION: */
897 #ifdef LDAP_THREAD_POOL_IMPLEMENTATION
898
899 int
900 ldap_pvt_thread_pool_init(
901         ldap_pvt_thread_pool_t *tpool,
902         int max_threads,
903         int max_pending )
904 {
905         int rc;
906         ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_init" );
907         rc = ldap_int_thread_pool_init( tpool, max_threads, max_pending );
908         if( rc ) {
909                 ERROR( rc, "ldap_pvt_thread_pool_init" );
910         } else {
911                 adjust_count( Idx_tpool, +1 );
912         }
913         return rc;
914 }
915
916 int
917 ldap_pvt_thread_pool_submit(
918         ldap_pvt_thread_pool_t *tpool,
919         ldap_pvt_thread_start_t *start_routine, void *arg )
920 {
921         int rc, has_pool;
922         ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_submit" );
923         has_pool = (tpool != NULL && *tpool != NULL);
924         rc = ldap_int_thread_pool_submit( tpool, start_routine, arg );
925         if( has_pool )
926                 ERROR_IF( rc, "ldap_pvt_thread_pool_submit" );
927         return rc;
928 }
929
930 int
931 ldap_pvt_thread_pool_maxthreads(
932         ldap_pvt_thread_pool_t *tpool,
933         int max_threads )
934 {
935         ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_maxthreads" );
936         return ldap_int_thread_pool_maxthreads( tpool, max_threads );
937 }
938
939 int
940 ldap_pvt_thread_pool_backload( ldap_pvt_thread_pool_t *tpool )
941 {
942         ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_backload" );
943         return ldap_int_thread_pool_backload( tpool );
944 }
945
946 int
947 ldap_pvt_thread_pool_destroy( ldap_pvt_thread_pool_t *tpool, int run_pending )
948 {
949         int rc, has_pool;
950         ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_destroy" );
951         has_pool = (tpool != NULL && *tpool != NULL);
952         rc = ldap_int_thread_pool_destroy( tpool, run_pending );
953         if( has_pool ) {
954                 if( rc ) {
955                         ERROR( rc, "ldap_pvt_thread_pool_destroy" );
956                 } else {
957                         adjust_count( Idx_tpool, -1 );
958                 }
959         }
960         return rc;
961 }
962
963 int
964 ldap_pvt_thread_pool_pause( ldap_pvt_thread_pool_t *tpool )
965 {
966         ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_pause" );
967         return ldap_int_thread_pool_pause( tpool );
968 }
969
970 int
971 ldap_pvt_thread_pool_resume( ldap_pvt_thread_pool_t *tpool )
972 {
973         ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_resume" );
974         return ldap_int_thread_pool_resume( tpool );
975 }
976
977 int
978 ldap_pvt_thread_pool_getkey(
979         void *xctx,
980         void *key,
981         void **data,
982         ldap_pvt_thread_pool_keyfree_t **kfree )
983 {
984 #if 0 /* Function is used by ch_free() via slap_sl_contxt() in slapd */
985         ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_getkey" );
986 #endif
987         return ldap_int_thread_pool_getkey( xctx, key, data, kfree );
988 }
989
990 int
991 ldap_pvt_thread_pool_setkey(
992         void *xctx,
993         void *key,
994         void *data,
995         ldap_pvt_thread_pool_keyfree_t *kfree )
996 {
997         int rc;
998         ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_setkey" );
999         rc = ldap_int_thread_pool_setkey( xctx, key, data, kfree );
1000         ERROR_IF( rc, "ldap_pvt_thread_pool_setkey" );
1001         return rc;
1002 }
1003
1004 void
1005 ldap_pvt_thread_pool_purgekey( void *key )
1006 {
1007         ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_purgekey" );
1008         ldap_int_thread_pool_purgekey( key );
1009 }
1010
1011 void *
1012 ldap_pvt_thread_pool_context( void )
1013 {
1014 #if 0 /* Function is used by ch_free() via slap_sl_contxt() in slapd */
1015         ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_context" );
1016 #endif
1017         return ldap_int_thread_pool_context();
1018 }
1019
1020 void
1021 ldap_pvt_thread_pool_context_reset( void *vctx )
1022 {
1023         ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_context_reset" );
1024         ldap_int_thread_pool_context_reset( vctx );
1025 }
1026
1027 #endif /* LDAP_THREAD_POOL_IMPLEMENTATION */
1028
1029 #endif /* LDAP_THREAD_DEBUG */