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