1 /* thr_debug.c - wrapper around the chosen thread wrapper, for debugging. */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 2005-2006 The OpenLDAP Foundation.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted only as authorized by the OpenLDAP
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>.
18 * This package provides three types of thread operation debugging:
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.
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.
31 * - Print a count of leaked thread resources after cleanup.
33 * Compile-time (./configure) setup: Macros defined in CPPFLAGS.
35 * LDAP_THREAD_DEBUG or LDAP_THREAD_DEBUG=2
36 * Enables debugging, but value & 2 turns off type wrapping.
38 * LDAP_UINTPTR_T=integer type to hold pointers, preferably unsigned.
39 * Used by dummy memory option "scramble". Default = unsigned long.
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).
48 * Run-time configuration: Environment variable LDAP_THREAD_DEBUG.
50 * The variable may contain a comma- or space-separated option list.
52 * off - Disable this package.
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.
75 * tracethreads - Report create/join/exit/kill of threads.
80 #if defined( LDAP_THREAD_DEBUG )
84 #include <ac/stdlib.h>
85 #include <ac/string.h>
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 */
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;
102 static int tracethreads;
104 static int threading_enabled;
107 Idx_unexited_thread, Idx_unjoined_thread, Idx_locked_mutex,
108 Idx_mutex, Idx_cond, Idx_rdwr, Idx_tpool, Idx_max
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"
115 static ldap_int_thread_mutex_t resource_mutexes[Idx_max];
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.
122 typedef struct ldap_debug_thread_s {
123 ldap_pvt_thread_t wrapped;
124 ldap_debug_usage_info_t usage;
127 } ldap_debug_thread_t;
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;
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));}
141 warn( const char *file, int line, const char *msg, const char *var, int val )
143 fprintf( stderr, "%s:%d: %s warning: %s is %d\n",
144 file, line, msg, var, val );
149 error( const char *file, int line, const char *msg, const char *var, int val )
152 fprintf( stderr, "%s:%d: %s error: %s is %d\n",
153 file, line, msg, var, val );
160 count_resource_leaks( void )
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" );
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] );
179 fprintf( stderr, "%s:%d: %s.\n", __FILE__, __LINE__, errbuf );
186 static const struct option_info_s {
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 },
201 { "tracethreads", &tracethreads, 1 },
204 const char *s = getenv( "LDAP_THREAD_DEBUG" );
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' ) {
214 fprintf( stderr, "Unknown $%s option '%.*s'\n",
215 "LDAP_THREAD_DEBUG", (int) optlen, s );
224 noabort = noerror = 1;
225 tracethreads = dupinit = 0;
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 )
237 fprintf( stderr, "Misconfigured for $%s %s. Using %s.\n",
238 "LDAP_THREAD_DEBUG", "scramble", "adjptr" );
239 wraptype = Wrap_adjptr;
242 unwrap_offset = -(wrap_offset = (wraptype == Wrap_adjptr));
249 thread_name( char *buf, int bufsize, ldap_pvt_thread_t thread )
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] );
261 exit_thread_message( const ldap_pvt_thread_t thread )
265 fprintf( stderr, "== Exiting thread %s ==\n",
266 thread_name( buf, sizeof(buf), thread ) );
271 #ifndef LDAP_THREAD_DEBUG_WRAP
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)
279 #define alloc_usage(ptr, msg) ((void) 0)
280 #define check_usage(ptr, msg) ((void) 0)
281 #define free_usage(ptr, msg) ((void) 0)
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())
290 #else /* LDAP_THREAD_DEBUG_WRAP */
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 */
298 static const ldap_int_thread_t ldap_debug_thread_none = LDAP_DEBUG_THREAD_NONE;
301 ldap_debug_thread_mutex_owner( ldap_pvt_thread_mutex_t *mutex )
303 return ldap_pvt_thread_equal( mutex->owner, ldap_pvt_thread_self() );
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 ) )
315 #define INITED_VALUE 0x12345678UL
316 #define INITED_BYTE_VALUE 0xd5
319 debug_already_initialized( const LDAP_UINTPTR_T *num )
321 /* Valid programs will access uninitialized memory if dupinit */
322 return dupinit && *num == INITED_VALUE;
326 alloc_usage( ldap_debug_usage_info_t *usage, const char *msg )
330 if( wraptype == Wrap_noalloc ) {
331 ERROR_IF( debug_already_initialized( &usage->num ), msg );
332 usage->num = INITED_VALUE;
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 );
341 usage->ptr = dummy + wrap_offset;
347 check_usage( ldap_debug_usage_info_t *usage, const char *msg )
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 );
355 ERROR_IF( !usage->ptr, msg );
356 ERROR_IF( usage->ptr[unwrap_offset] != INITED_BYTE_VALUE, msg );
361 free_usage( ldap_debug_usage_info_t *usage, const char *msg )
363 if( wraptype == Wrap_noalloc ) {
364 usage->num = ~(LDAP_UINTPTR_T)INITED_VALUE;
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;
374 #define with_threads_lock(statement) { \
376 int rc_wtl_ = ldap_int_thread_mutex_lock( &thread_info_mutex ); \
377 assert( rc_wtl_ == 0 ); \
381 int rc_wtl_ = ldap_int_thread_mutex_unlock( &thread_info_mutex ); \
382 assert( rc_wtl_ == 0 ); \
386 static ldap_debug_thread_t *
387 get_new_thread_info( const char *msg )
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) );
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++;
404 alloc_usage( &thread_info[thread_info_used]->usage, msg );
405 return thread_info[thread_info_used++];
410 ldap_debug_thread_t *t,
411 const ldap_pvt_thread_t *thread,
415 t->wrapped = *thread;
416 t->detached = detached;
421 remove_thread_info( ldap_debug_thread_t *t, const char *msg )
424 ldap_debug_thread_t *last;
426 free_usage( &t->usage, msg );
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;
436 ldap_debug_thread_t *
437 get_thread_info( ldap_pvt_thread_t *thread, const char *msg )
440 ldap_debug_thread_t *t;
443 for( i = 0; i < thread_info_used; i++ ) {
444 if( ldap_pvt_thread_equal( *thread, thread_info[i]->wrapped ) )
447 ERROR_IF( i == thread_info_used, msg );
449 check_usage( &t->usage, msg );
454 exiting_thread( const char *msg )
457 ldap_pvt_thread_t thread;
458 thread = ldap_pvt_thread_self();
459 exit_thread_message( thread );
461 ldap_debug_thread_t *t = get_thread_info( &thread, msg );
463 remove_thread_info( t, msg );
468 #endif /* LDAP_THREAD_DEBUG_WRAP */
472 adjust_count( int which, int adjust )
479 rc = ldap_int_thread_mutex_lock( &resource_mutexes[which] );
481 resource_counts[which] += adjust;
482 rc = ldap_int_thread_mutex_unlock( &resource_mutexes[which] );
485 fputs( "...more ldap_debug_thread activity after exit...\n", stderr );
486 count = Count_reported_more;
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;
497 /* Wrappers for LDAP_THREAD_IMPLEMENTATION: */
499 /* Used instead of ldap_int_thread_initialize by ldap_pvt_thread_initialize */
501 ldap_debug_thread_initialize( void )
506 ERROR_IF( threading_enabled, "ldap_debug_thread_initialize" );
507 threading_enabled = 1;
508 rc = ldap_int_thread_initialize();
510 ERROR( rc, "ldap_debug_thread_initialize:threads" );
511 threading_enabled = 0;
513 rc2 = ldap_int_thread_mutex_init( &thread_info_mutex );
515 if( count != Count_no ) {
516 for( i = rc2 = 0; i < Idx_max; i++ )
517 rc2 |= ldap_int_thread_mutex_init( &resource_mutexes[i] );
519 /* FIXME: Only for static libldap_r as in init.c? If so, why? */
520 atexit( count_resource_leaks );
526 /* Used instead of ldap_int_thread_destroy by ldap_pvt_thread_destroy */
528 ldap_debug_thread_destroy( void )
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();
535 ERROR( rc, "ldap_debug_thread_destroy:threads" );
537 threading_enabled = 0;
543 ldap_pvt_thread_set_concurrency( int n )
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" );
553 ldap_pvt_thread_get_concurrency( void )
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" );
563 ldap_pvt_thread_sleep( unsigned int interval )
566 ERROR_IF( !threading_enabled, "ldap_pvt_thread_sleep" );
567 rc = ldap_int_thread_sleep( interval );
568 ERROR_IF( rc, "ldap_pvt_thread_sleep" );
573 ldap_pvt_thread_create(
574 ldap_pvt_thread_t *thread,
576 void *(*start_routine)( void * ),
580 ERROR_IF( !threading_enabled, "ldap_pvt_thread_create" );
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 );
588 ERROR( rc, "ldap_pvt_thread_create" );
589 remove_thread_info( t, "ldap_pvt_thread_init" );
591 update_thread_info( t, thread, detach );
597 fprintf( stderr, "== Created thread %s%s ==\n",
598 thread_name( buf, sizeof(buf), *thread ),
599 detach ? " (detached)" : "" );
601 adjust_count( Idx_unexited_thread, +1 );
603 adjust_count( Idx_unjoined_thread, +1 );
609 ldap_pvt_thread_exit( void *retval )
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 );
618 ldap_pvt_thread_join( ldap_pvt_thread_t thread, void **thread_return )
621 ldap_debug_thread_t *t;
622 ERROR_IF( !threading_enabled, "ldap_pvt_thread_join" );
625 fprintf( stderr, "== Joining thread %s ==\n",
626 thread_name( buf, sizeof(buf), thread ) );
629 t = get_thread_info( &thread, "ldap_pvt_thread_join" ) );
630 rc = ldap_int_thread_join( thread, thread_return );
632 ERROR( rc, "ldap_pvt_thread_join" );
635 remove_thread_info( t, "ldap_pvt_thread_join" ) );
636 adjust_count( Idx_unjoined_thread, -1 );
642 ldap_pvt_thread_kill( ldap_pvt_thread_t thread, int signo )
645 ERROR_IF( !threading_enabled, "ldap_pvt_thread_kill" );
648 fprintf( stderr, "== Killing thread %s (sig %i) ==\n",
649 thread_name( buf, sizeof(buf), thread ), signo );
651 rc = ldap_int_thread_kill( thread, signo );
652 ERROR_IF( rc, "ldap_pvt_thread_kill" );
657 ldap_pvt_thread_yield( void )
660 ERROR_IF( !threading_enabled, "ldap_pvt_thread_yield" );
661 rc = ldap_int_thread_yield();
662 ERROR_IF( rc, "ldap_pvt_thread_yield" );
667 ldap_pvt_thread_self( void )
669 #if 0 /* Function is used by ch_free() via slap_sl_contxt() in slapd */
670 ERROR_IF( !threading_enabled, "ldap_pvt_thread_self" );
672 return ldap_int_thread_self();
676 ldap_pvt_thread_cond_init( ldap_pvt_thread_cond_t *cond )
679 alloc_usage( &cond->usage, "ldap_pvt_thread_cond_init" );
680 rc = ldap_int_thread_cond_init( WRAPPED( cond ) );
682 ERROR( rc, "ldap_pvt_thread_cond_init" );
683 free_usage( &cond->usage, "ldap_pvt_thread_cond_init" );
685 adjust_count( Idx_cond, +1 );
691 ldap_pvt_thread_cond_destroy( ldap_pvt_thread_cond_t *cond )
694 check_usage( &cond->usage, "ldap_pvt_thread_cond_destroy" );
695 rc = ldap_int_thread_cond_destroy( WRAPPED( cond ) );
697 ERROR( rc, "ldap_pvt_thread_cond_destroy" );
699 free_usage( &cond->usage, "ldap_pvt_thread_cond_destroy" );
700 adjust_count( Idx_cond, -1 );
706 ldap_pvt_thread_cond_signal( ldap_pvt_thread_cond_t *cond )
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" );
716 ldap_pvt_thread_cond_broadcast( ldap_pvt_thread_cond_t *cond )
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" );
726 ldap_pvt_thread_cond_wait(
727 ldap_pvt_thread_cond_t *cond,
728 ldap_pvt_thread_mutex_t *mutex )
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 );
739 adjust_count( Idx_locked_mutex, +1 );
740 ERROR_IF( rc, "ldap_pvt_thread_cond_wait" );
745 ldap_pvt_thread_mutex_init( ldap_pvt_thread_mutex_t *mutex )
748 alloc_usage( &mutex->usage, "ldap_pvt_thread_mutex_init" );
749 rc = ldap_int_thread_mutex_init( WRAPPED( mutex ) );
751 ERROR( rc, "ldap_pvt_thread_mutex_init" );
752 free_usage( &mutex->usage, "ldap_pvt_thread_mutex_init" );
754 RESET_OWNER( mutex );
755 adjust_count( Idx_mutex, +1 );
761 ldap_pvt_thread_mutex_destroy( ldap_pvt_thread_mutex_t *mutex )
764 check_usage( &mutex->usage, "ldap_pvt_thread_mutex_destroy" );
765 ASSERT_NO_OWNER( mutex );
766 rc = ldap_int_thread_mutex_destroy( WRAPPED( mutex ) );
768 ERROR( rc, "ldap_pvt_thread_mutex_destroy" );
769 /* mutex->owner may now be scrambled, sorry */
771 free_usage( &mutex->usage, "ldap_pvt_thread_mutex_destroy" );
772 RESET_OWNER( mutex );
773 adjust_count( Idx_mutex, -1 );
779 ldap_pvt_thread_mutex_lock( ldap_pvt_thread_mutex_t *mutex )
782 check_usage( &mutex->usage, "ldap_pvt_thread_mutex_lock" );
783 rc = ldap_int_thread_mutex_lock( WRAPPED( mutex ) );
785 ERROR_IF( rc, "ldap_pvt_thread_mutex_lock" );
787 ASSERT_NO_OWNER( mutex );
789 adjust_count( Idx_locked_mutex, +1 );
795 ldap_pvt_thread_mutex_trylock( ldap_pvt_thread_mutex_t *mutex )
798 check_usage( &mutex->usage, "ldap_pvt_thread_mutex_trylock" );
799 rc = ldap_int_thread_mutex_trylock( WRAPPED( mutex ) );
801 ASSERT_NO_OWNER( mutex );
803 adjust_count( Idx_locked_mutex, +1 );
809 ldap_pvt_thread_mutex_unlock( ldap_pvt_thread_mutex_t *mutex )
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 ) );
817 ERROR_IF( rc, "ldap_pvt_thread_mutex_unlock" );
819 adjust_count( Idx_locked_mutex, -1 );
825 /* Wrappers for LDAP_THREAD_RDWR_IMPLEMENTATION: */
828 ldap_pvt_thread_rdwr_init( ldap_pvt_thread_rdwr_t *rwlock )
831 alloc_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_init" );
832 rc = ldap_int_thread_rdwr_init( WRAPPED( rwlock ) );
834 ERROR( rc, "ldap_pvt_thread_rdwr_init" );
835 free_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_init" );
837 adjust_count( Idx_rdwr, +1 );
843 ldap_pvt_thread_rdwr_destroy( ldap_pvt_thread_rdwr_t *rwlock )
846 check_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_destroy" );
847 rc = ldap_int_thread_rdwr_destroy( WRAPPED( rwlock ) );
849 ERROR( rc, "ldap_pvt_thread_rdwr_destroy" );
851 free_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_destroy" );
852 adjust_count( Idx_rdwr, -1 );
858 ldap_pvt_thread_rdwr_rlock( ldap_pvt_thread_rdwr_t *rwlock )
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" );
868 ldap_pvt_thread_rdwr_rtrylock( ldap_pvt_thread_rdwr_t *rwlock )
870 check_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_rtrylock" );
871 return ldap_int_thread_rdwr_rtrylock( WRAPPED( rwlock ) );
875 ldap_pvt_thread_rdwr_runlock( ldap_pvt_thread_rdwr_t *rwlock )
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" );
885 ldap_pvt_thread_rdwr_wlock( ldap_pvt_thread_rdwr_t *rwlock )
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" );
895 ldap_pvt_thread_rdwr_wtrylock( ldap_pvt_thread_rdwr_t *rwlock )
897 check_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_wtrylock" );
898 return ldap_int_thread_rdwr_wtrylock( WRAPPED( rwlock ) );
902 ldap_pvt_thread_rdwr_wunlock( ldap_pvt_thread_rdwr_t *rwlock )
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" );
911 #ifdef LDAP_RDWR_DEBUG
914 ldap_pvt_thread_rdwr_readers( ldap_pvt_thread_rdwr_t *rwlock )
916 check_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_readers" );
917 return ldap_int_thread_rdwr_readers( WRAPPED( rwlock ) );
921 ldap_pvt_thread_rdwr_writers( ldap_pvt_thread_rdwr_t *rwlock )
923 check_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_writers" );
924 return ldap_int_thread_rdwr_writers( WRAPPED( rwlock ) );
928 ldap_pvt_thread_rdwr_active( ldap_pvt_thread_rdwr_t *rwlock )
930 check_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_active" );
931 return ldap_int_thread_rdwr_active( WRAPPED( rwlock ) );
934 #endif /* LDAP_RDWR_DEBUG */
937 /* Some wrappers for LDAP_THREAD_POOL_IMPLEMENTATION: */
938 #ifdef LDAP_THREAD_POOL_IMPLEMENTATION
941 ldap_pvt_thread_pool_init(
942 ldap_pvt_thread_pool_t *tpool,
947 ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_init" );
948 rc = ldap_int_thread_pool_init( tpool, max_threads, max_pending );
950 ERROR( rc, "ldap_pvt_thread_pool_init" );
952 adjust_count( Idx_tpool, +1 );
958 ldap_pvt_thread_pool_submit(
959 ldap_pvt_thread_pool_t *tpool,
960 ldap_pvt_thread_start_t *start_routine, void *arg )
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 );
967 ERROR_IF( rc, "ldap_pvt_thread_pool_submit" );
972 ldap_pvt_thread_pool_maxthreads(
973 ldap_pvt_thread_pool_t *tpool,
976 ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_maxthreads" );
977 return ldap_int_thread_pool_maxthreads( tpool, max_threads );
981 ldap_pvt_thread_pool_backload( ldap_pvt_thread_pool_t *tpool )
983 ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_backload" );
984 return ldap_int_thread_pool_backload( tpool );
988 ldap_pvt_thread_pool_destroy( ldap_pvt_thread_pool_t *tpool, int run_pending )
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 );
996 ERROR( rc, "ldap_pvt_thread_pool_destroy" );
998 adjust_count( Idx_tpool, -1 );
1005 ldap_pvt_thread_pool_pause( ldap_pvt_thread_pool_t *tpool )
1007 ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_pause" );
1008 return ldap_int_thread_pool_pause( tpool );
1012 ldap_pvt_thread_pool_resume( ldap_pvt_thread_pool_t *tpool )
1014 ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_resume" );
1015 return ldap_int_thread_pool_resume( tpool );
1019 ldap_pvt_thread_pool_getkey(
1023 ldap_pvt_thread_pool_keyfree_t **kfree )
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" );
1028 return ldap_int_thread_pool_getkey( xctx, key, data, kfree );
1032 ldap_pvt_thread_pool_setkey(
1036 ldap_pvt_thread_pool_keyfree_t *kfree )
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" );
1046 ldap_pvt_thread_pool_purgekey( void *key )
1048 ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_purgekey" );
1049 ldap_int_thread_pool_purgekey( key );
1053 ldap_pvt_thread_pool_context( void )
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" );
1058 return ldap_int_thread_pool_context();
1062 ldap_pvt_thread_pool_context_reset( void *vctx )
1064 ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_context_reset" );
1065 ldap_int_thread_pool_context_reset( vctx );
1068 #endif /* LDAP_THREAD_POOL_IMPLEMENTATION */
1070 #endif /* LDAP_THREAD_DEBUG */