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 several types of thread operation debugging:
20 * - Check the results of operations on threads, mutexes, condition
21 * variables and read/write locks. Also check some thread pool
22 * operations, but not those for which failure can happen in normal
25 * - Wrap those types except threads and pools in structs with state
26 * information, and check that on all operations:
28 * + Check that the resources are initialized and are only used at
29 * their original address (i.e. not realloced or copied).
31 * + Check the owner (thread ID) on mutex operations.
33 * + Optionally allocate a reference to a byte of dummy memory.
34 * This lets malloc debuggers see some incorrect use as memory
35 * leaks, access to freed memory, etc.
37 * - Print an error message and by default abort() upon errors.
39 * - Print a count of leaked thread resources after cleanup.
41 * Compile-time (./configure) setup: Macros defined in CPPFLAGS.
43 * LDAP_THREAD_DEBUG or LDAP_THREAD_DEBUG=2
44 * Enables debugging, but value & 2 turns off type wrapping.
46 * LDAP_UINTPTR_T=integer type to hold pointers, preferably unsigned.
47 * Used by dummy memory option "scramble". Default = unsigned long.
49 * LDAP_DEBUG_THREAD_NONE = initializer for a "no thread" thread ID.
51 * In addition, you may need to set up an implementation-specific way
52 * to enable whatever error checking your thread library provides.
53 * Currently only implemented for Posix threads (pthreads), where
54 * you may need to define LDAP_INT_THREAD_MUTEXATTR. The default
55 * is PTHREAD_MUTEX_ERRORCHECK, or PTHREAD_MUTEX_ERRORCHECK_NP for
56 * Linux threads. See pthread_mutexattr_settype(3).
58 * Run-time configuration:
60 * Setup of memory debugging tools:
61 * Tools that report uninitialized memory accesses should disable
62 * such warnings about the function debug_already_initialized().
63 * Alternatively, include "noreinit" (below) in $LDAP_THREAD_DEBUG.
65 * Environment variable $LDAP_THREAD_DEBUG:
66 * The variable may contain a comma- or space-separated option list.
68 * off - Disable this package. (It still slows things down).
69 * tracethreads - Report create/join/exit/kill of threads.
70 * noabort - Do not abort() on errors.
71 * noerror - Do not report errors. Implies noabort.
72 * nocount - Do not report counts of unreleased resources.
73 * nosync - Disable tests that use synchronizaion and thus
74 * clearly affect thread scheduling:
75 * Implies nocount, and cancels threadID if that is set.
76 * Note that if you turn on tracethreads or malloc
77 * debugging, these also use library calls which may
78 * affect thread scheduling (fprintf and malloc).
79 * The following options do not apply if type wrapping is disabled:
80 * nomem - Do not check memory operations.
81 * Implies noreinit,noalloc.
82 * noreinit - Do not catch reinitialization of existing resources.
83 * (That test accesses uninitialized memory).
84 * threadID - Trace thread IDs. Currently mostly useless.
85 * Malloc debugging -- allocate dummy memory for initialized
86 * resources, so malloc debuggers will report them as memory leaks:
87 * noalloc - Default. Do not allocate dummy memory.
88 * alloc - Store a pointer to dummy memory. However, leak
89 * detectors might not catch unreleased resources in
91 * scramble - Store bitwise complement of dummy memory pointer.
92 * That never escapes memory leak detectors -
93 * but detection while the program is running will
94 * report active resources as leaks. Do not
95 * use this if a garbage collector is in use:-)
96 * adjptr - Point to end of dummy memory.
97 * Purify reports these as "potential leaks" (PLK).
98 * I have not checked other malloc debuggers.
101 #include "portable.h"
103 #if defined( LDAP_THREAD_DEBUG )
106 #include <ac/errno.h>
107 #include <ac/stdlib.h>
108 #include <ac/string.h>
110 #include "ldap_pvt_thread.h" /* Get the thread interface */
111 #define LDAP_THREAD_IMPLEMENTATION
112 #define LDAP_THREAD_DEBUG_IMPLEMENTATION
113 #define LDAP_THREAD_RDWR_IMPLEMENTATION
114 #define LDAP_THREAD_POOL_IMPLEMENTATION
115 #include "ldap_thr_debug.h" /* Get the underlying implementation */
117 #ifndef LDAP_THREAD_DEBUG_WRAP
118 #undef LDAP_THREAD_DEBUG_THREAD_ID
119 #elif !defined LDAP_THREAD_DEBUG_THREAD_ID
120 #define LDAP_THREAD_DEBUG_THREAD_ID 1
123 /* Use native malloc - the OpenLDAP wrappers may defeat malloc debuggers */
130 /* Options from environment variable $LDAP_THREAD_DEBUG */
131 enum { Count_no = 0, Count_yes, Count_reported, Count_reported_more };
132 static int count = Count_yes;
133 #ifdef LDAP_THREAD_DEBUG_WRAP
134 enum { Wrap_noalloc, Wrap_alloc, Wrap_scramble, Wrap_adjptr };
135 static int wraptype = Wrap_noalloc, wrap_offset, unwrap_offset;
136 static int nomem, noreinit;
138 #if LDAP_THREAD_DEBUG_THREAD_ID +0
141 enum { threadID = 0 };
143 static int nodebug, noabort, noerror, nosync, tracethreads;
144 static int options_done;
147 /* ldap_pvt_thread_initialize() called, ldap_pvt_thread_destroy() not called */
148 static int threading_enabled;
151 /* Resource counts */
153 Idx_unexited_thread, Idx_unjoined_thread, Idx_locked_mutex,
154 Idx_mutex, Idx_cond, Idx_rdwr, Idx_tpool, Idx_max
156 static int resource_counts[Idx_max];
157 static const char *const resource_names[] = {
158 "unexited threads", "unjoined threads", "locked mutexes",
159 "mutexes", "conds", "rdwrs", "thread pools"
161 static ldap_int_thread_mutex_t resource_mutexes[Idx_max];
164 /* Hide pointers from malloc debuggers. */
165 #define SCRAMBLE(ptr) (~(LDAP_UINTPTR_T) (ptr))
166 #define UNSCRAMBLE_usagep(num) ((ldap_debug_usage_info_t *) ~(num))
167 #define UNSCRAMBLE_dummyp(num) ((unsigned char *) ~(num))
170 #define WARN(var, msg) (warn (__FILE__, __LINE__, (msg), #var, (var)))
171 #define WARN_IF(rc, msg) {if (rc) warn (__FILE__, __LINE__, (msg), #rc, (rc));}
173 #define ERROR(var, msg) { \
175 errmsg(__FILE__, __LINE__, (msg), #var, (var)); \
176 if( !noabort ) abort(); \
180 #define ERROR_IF(rc, msg) { \
184 errmsg(__FILE__, __LINE__, (msg), #rc, rc_); \
185 if( !noabort ) abort(); \
190 #ifdef LDAP_THREAD_DEBUG_WRAP
191 #define MEMERROR_IF(rc, msg, mem_act) { \
195 errmsg(__FILE__, __LINE__, (msg), #rc, rc_); \
196 if( wraptype != Wrap_noalloc ) { mem_act; } \
197 if( !noabort ) abort(); \
201 #endif /* LDAP_THREAD_DEBUG_WRAP */
205 warn( const char *file, int line, const char *msg, const char *var, int val )
208 (strpbrk( var, "!=" )
209 ? "%s:%d: %s warning: %s\n"
210 : "%s:%d: %s warning: %s is %d\n"),
211 file, line, msg, var, val );
216 errmsg( const char *file, int line, const char *msg, const char *var, int val )
219 (strpbrk( var, "!=" )
220 ? "%s:%d: %s error: %s\n"
221 : "%s:%d: %s error: %s is %d\n"),
222 file, line, msg, var, val );
226 count_resource_leaks( void )
230 if( count == Count_yes ) {
231 count = Count_reported;
232 #if 0 /* Could break if there are still threads after atexit */
233 for( i = j = 0; i < Idx_max; i++ )
234 j |= ldap_int_thread_mutex_destroy( &resource_mutexes[i] );
235 WARN_IF( j, "ldap_debug_thread_destroy:mutexes" );
237 for( i = j = 0; i < Idx_max; i++ )
238 if( resource_counts[i] )
239 j += sprintf( errbuf + j, ", %d %s",
240 resource_counts[i], resource_names[i] );
242 fprintf( stderr, "== thr_debug: Leaked%s. ==\n", errbuf + 1 );
249 static const struct option_info_s {
253 { "off", &nodebug, 1 },
254 { "noabort", &noabort, 1 },
255 { "noerror", &noerror, 1 },
256 { "nocount", &count, Count_no },
257 { "nosync", &nosync, 1 },
258 #if LDAP_THREAD_DEBUG_THREAD_ID +0
259 { "threadID", &threadID, 1 },
261 #ifdef LDAP_THREAD_DEBUG_WRAP
262 { "nomem", &nomem, 1 },
263 { "noreinit", &noreinit, 1 },
264 { "noalloc", &wraptype, Wrap_noalloc },
265 { "alloc", &wraptype, Wrap_alloc },
266 { "adjptr", &wraptype, Wrap_adjptr },
267 { "scramble", &wraptype, Wrap_scramble },
269 { "tracethreads", &tracethreads, 1 },
272 const char *s = getenv( "LDAP_THREAD_DEBUG" );
274 while( *(s += strspn( s, ", \t\r\n" )) != '\0' ) {
275 size_t optlen = strcspn( s, ", \t\r\n" );
276 const struct option_info_s *oi;
277 for( oi = option_info; oi->name; oi++ ) {
278 if( strncasecmp( oi->name, s, optlen ) == 0 ) {
279 if( oi->name && oi->name[optlen] == '\0' ) {
283 "== thr_debug: Unknown $%s option '%.*s' ==\n",
284 "LDAP_THREAD_DEBUG", (int) optlen, s );
294 nosync = noerror = 1;
300 #if LDAP_THREAD_DEBUG_THREAD_ID +0
304 #ifdef LDAP_THREAD_DEBUG_WRAP
308 static const ldap_debug_usage_info_t usage;
309 if( sizeof(LDAP_UINTPTR_T) < sizeof(unsigned char *)
310 || sizeof(LDAP_UINTPTR_T) < sizeof(ldap_debug_usage_info_t *)
311 || UNSCRAMBLE_usagep( SCRAMBLE( &usage ) ) != &usage
312 || UNSCRAMBLE_dummyp( SCRAMBLE( (unsigned char *) 0 ) ) )
314 fputs( "== thr_debug: Memory checks unsupported, "
315 "adding nomem to $LDAP_THREAD_DEBUG ==\n", stderr );
321 wraptype = Wrap_noalloc;
323 unwrap_offset = -(wrap_offset = (wraptype == Wrap_adjptr));
329 #ifndef LDAP_THREAD_DEBUG_WRAP
331 #define WRAPPED(ptr) (ptr)
332 #define GET_OWNER(ptr) 0
333 #define SET_OWNER(ptr, thread) ((void) 0)
334 #define RESET_OWNER(ptr) ((void) 0)
335 #define ASSERT_OWNER(ptr, msg) ((void) 0)
336 #define ASSERT_NO_OWNER(ptr, msg) ((void) 0)
338 #define init_usage(ptr, msg) ((void) 0)
339 #define check_usage(ptr, msg) ((void) 0)
340 #define destroy_usage(ptr) ((void) 0)
342 #else /* LDAP_THREAD_DEBUG_WRAP */
344 /* Specialize this if the initializer is not appropriate. */
345 /* The ASSERT_NO_OWNER() definition may also need an override. */
346 #ifndef LDAP_DEBUG_THREAD_NONE
347 #define LDAP_DEBUG_THREAD_NONE { -1 } /* "no thread" ldap_int_thread_t value */
350 static const ldap_int_thread_t ldap_debug_thread_none = LDAP_DEBUG_THREAD_NONE;
352 #define THREAD_MUTEX_OWNER(mutex) \
353 ldap_int_thread_equal( (mutex)->owner, ldap_int_thread_self() )
356 ldap_debug_thread_assert_mutex_owner(
360 ldap_pvt_thread_mutex_t *mutex )
362 if( !(noerror || THREAD_MUTEX_OWNER( mutex )) ) {
363 errmsg( file, line, msg, "ASSERT_MUTEX_OWNER", 0 );
364 if( !noabort ) abort();
368 #define WRAPPED(ptr) (&(ptr)->wrapped)
369 #define GET_OWNER(ptr) ((ptr)->owner)
370 #define SET_OWNER(ptr, thread) ((ptr)->owner = (thread))
371 #define RESET_OWNER(ptr) ((ptr)->owner = ldap_debug_thread_none)
372 #define ASSERT_OWNER(ptr, msg) ERROR_IF( !THREAD_MUTEX_OWNER( ptr ), msg )
373 #ifndef ASSERT_NO_OWNER
374 #define ASSERT_NO_OWNER(ptr, msg) ERROR_IF( \
375 !ldap_int_thread_equal( (ptr)->owner, ldap_debug_thread_none ), msg )
378 /* Try to provoke memory access error (for malloc debuggers) */
379 #define PEEK(mem) {if (-*(volatile const unsigned char *)(mem)) debug_noop();}
381 static void debug_noop( void );
382 static int debug_already_initialized( const ldap_debug_usage_info_t *usage );
384 /* Names used to give clearer error messages */
385 #define IS_COPY_OR_MOVED(usage) ((usage)->self != SCRAMBLE( usage ))
386 enum { Is_destroyed = 1 };
388 #define DUMMY_ADDR(usage) \
389 (wraptype == Wrap_scramble \
390 ? UNSCRAMBLE_dummyp( (usage)->mem.num ) \
391 : (usage)->mem.ptr + unwrap_offset)
393 /* Mark resource as initialized */
395 init_usage( ldap_debug_usage_info_t *usage, const char *msg )
401 MEMERROR_IF( debug_already_initialized( usage ), msg, {
402 /* Provoke malloc debuggers */
403 unsigned char *dummy = DUMMY_ADDR( usage );
409 usage->self = SCRAMBLE( usage );
410 if( wraptype != Wrap_noalloc ) {
411 unsigned char *dummy = malloc( 1 );
412 assert( dummy != NULL );
413 if( wraptype == Wrap_scramble ) {
414 usage->mem.num = SCRAMBLE( dummy );
415 assert( UNSCRAMBLE_dummyp( usage->mem.num ) == dummy );
417 usage->mem.ptr = dummy + wrap_offset;
421 usage->magic = ldap_debug_magic;
422 usage->state = ldap_debug_state_inited;
425 /* Check that resource is initialized and not copied/realloced */
427 check_usage( const ldap_debug_usage_info_t *usage, const char *msg )
429 if( usage->magic != ldap_debug_magic ) {
430 ERROR( usage->magic, msg );
433 switch( usage->state ) {
434 case ldap_debug_state_destroyed:
435 MEMERROR_IF( Is_destroyed, msg, {
436 PEEK( DUMMY_ADDR( usage ) );
440 ERROR( usage->state, msg );
442 case ldap_debug_state_inited:
444 MEMERROR_IF( IS_COPY_OR_MOVED( usage ), msg, {
445 PEEK( DUMMY_ADDR( usage ) );
446 PEEK( UNSCRAMBLE_usagep( usage->self ) );
453 /* Mark resource as destroyed. */
454 /* Does not check for errors, call check_usage()/init_usage() first. */
456 destroy_usage( ldap_debug_usage_info_t *usage )
458 if( usage->state == ldap_debug_state_inited ) {
459 if( wraptype != Wrap_noalloc ) {
460 free( DUMMY_ADDR( usage ) );
461 /* Do not reset the DUMMY_ADDR, leave it for malloc debuggers
462 * in case the resource is used after it is freed. */
464 usage->state = ldap_debug_state_destroyed;
468 /* Define these after they are used, so they are hopefully not inlined */
475 /* Return true if the resource is initialized and not copied/realloced. */
476 /* Valid programs access uninitialized memory here unless "noreinit". */
478 debug_already_initialized( const ldap_debug_usage_info_t *usage )
480 return (usage->state == ldap_debug_state_inited &&
481 !IS_COPY_OR_MOVED( usage ) &&
482 usage->magic == ldap_debug_magic);
485 #endif /* LDAP_THREAD_DEBUG_WRAP */
488 #if !(LDAP_THREAD_DEBUG_THREAD_ID +0)
490 typedef int ldap_debug_thread_t;
491 #define init_thread_info() {}
492 #define with_thread_info_lock(statements) { statements; }
493 #define thread_info_detached(t) 0
494 #define add_thread_info(msg, thr, det) ((void) 0)
495 #define remove_thread_info(tinfo, msg) ((void) 0)
496 #define get_thread_info(thread, msg) NULL
498 #else /* LDAP_THREAD_DEBUG_THREAD_ID */
501 * Thread ID tracking. Currently acieves little.
502 * Should be either expanded or deleted.
506 * Array of threads. Used instead of making ldap_pvt_thread_t a wrapper
507 * around ldap_int_thread_t, which would slow down ldap_pvt_thread_self().
510 ldap_pvt_thread_t wrapped;
511 ldap_debug_usage_info_t usage;
514 } ldap_debug_thread_t;
516 static ldap_debug_thread_t **thread_info;
517 static unsigned int thread_info_size, thread_info_used;
518 static ldap_int_thread_mutex_t thread_info_mutex;
520 #define init_thread_info() { \
522 int mutex_init_rc = ldap_int_thread_mutex_init( &thread_info_mutex ); \
523 assert( mutex_init_rc == 0 ); \
527 #define with_thread_info_lock(statements) { \
528 int rc_wtl_ = ldap_int_thread_mutex_lock( &thread_info_mutex ); \
529 assert( rc_wtl_ == 0 ); \
531 rc_wtl_ = ldap_int_thread_mutex_unlock( &thread_info_mutex ); \
532 assert( rc_wtl_ == 0 ); \
535 #define thread_info_detached(t) ((t)->detached)
540 const ldap_pvt_thread_t *thread,
543 ldap_debug_thread_t *t;
544 if( thread_info_used >= thread_info_size ) {
545 unsigned int more = thread_info_size + 8;
546 unsigned int new_size = thread_info_size + more;
547 t = calloc( more, sizeof(ldap_debug_thread_t) );
549 thread_info = realloc( thread_info, new_size * sizeof(*thread_info) );
550 assert( thread_info != NULL );
551 while( thread_info_size < new_size ) {
552 t->idx = thread_info_size;
553 thread_info[thread_info_size++] = t++;
556 t = thread_info[thread_info_used];
557 init_usage( &t->usage, msg );
558 t->wrapped = *thread;
559 t->detached = detached;
564 remove_thread_info( ldap_debug_thread_t *t, const char *msg )
566 ldap_debug_thread_t *last;
568 check_usage( &t->usage, msg );
569 destroy_usage( &t->usage );
571 assert( thread_info[idx] == t );
572 last = thread_info[--thread_info_used];
573 assert( last->idx == thread_info_used );
574 (thread_info[idx] = last)->idx = idx;
575 (thread_info[thread_info_used] = t )->idx = thread_info_used;
578 ldap_debug_thread_t *
579 get_thread_info( ldap_pvt_thread_t *thread, const char *msg )
582 ldap_debug_thread_t *t;
583 for( i = 0; i < thread_info_used; i++ ) {
584 if( ldap_pvt_thread_equal( *thread, thread_info[i]->wrapped ) )
587 ERROR_IF( i == thread_info_used, msg );
589 check_usage( &t->usage, msg );
593 #endif /* LDAP_THREAD_DEBUG_THREAD_ID */
597 thread_name( char *buf, int bufsize, ldap_pvt_thread_t thread )
601 if( bufsize > 2*sizeof(thread) )
602 bufsize = 2*sizeof(thread);
603 for( i = 0; i < bufsize; i += 2 )
604 snprintf( buf+i, 3, "%02x", ((unsigned char *)&thread)[i/2] );
609 /* Add <adjust> (+/-1) to resource count <which> unless "nocount". */
611 adjust_count( int which, int adjust )
618 rc = ldap_int_thread_mutex_lock( &resource_mutexes[which] );
620 resource_counts[which] += adjust;
621 rc = ldap_int_thread_mutex_unlock( &resource_mutexes[which] );
624 fputs( "== thr_debug: More thread activity after exit ==\n", stderr );
625 count = Count_reported_more;
627 case Count_reported_more:
628 /* Not used, but result might be inspected with debugger */
629 /* (Hopefully threading is disabled by now...) */
630 resource_counts[which] += adjust;
636 /* Wrappers for LDAP_THREAD_IMPLEMENTATION: */
638 /* Used instead of ldap_int_thread_initialize by ldap_pvt_thread_initialize */
640 ldap_debug_thread_initialize( void )
645 ERROR_IF( threading_enabled, "ldap_debug_thread_initialize" );
646 threading_enabled = 1;
647 rc = ldap_int_thread_initialize();
649 ERROR( rc, "ldap_debug_thread_initialize:threads" );
650 threading_enabled = 0;
653 if( count != Count_no ) {
654 for( i = rc2 = 0; i < Idx_max; i++ )
655 rc2 |= ldap_int_thread_mutex_init( &resource_mutexes[i] );
657 /* FIXME: Only for static libldap_r as in init.c? If so, why? */
658 atexit( count_resource_leaks );
664 /* Used instead of ldap_int_thread_destroy by ldap_pvt_thread_destroy */
666 ldap_debug_thread_destroy( void )
669 ERROR_IF( !threading_enabled, "ldap_debug_thread_destroy" );
670 /* sleep(1) -- need to wait for thread pool to finish? */
671 rc = ldap_int_thread_destroy();
673 ERROR( rc, "ldap_debug_thread_destroy:threads" );
675 threading_enabled = 0;
681 ldap_pvt_thread_set_concurrency( int n )
684 ERROR_IF( !threading_enabled, "ldap_pvt_thread_set_concurrency" );
685 rc = ldap_int_thread_set_concurrency( n );
686 ERROR_IF( rc, "ldap_pvt_thread_set_concurrency" );
691 ldap_pvt_thread_get_concurrency( void )
694 ERROR_IF( !threading_enabled, "ldap_pvt_thread_get_concurrency" );
695 rc = ldap_int_thread_get_concurrency();
696 ERROR_IF( rc, "ldap_pvt_thread_get_concurrency" );
701 ldap_pvt_thread_sleep( unsigned int interval )
704 ERROR_IF( !threading_enabled, "ldap_pvt_thread_sleep" );
705 rc = ldap_int_thread_sleep( interval );
706 ERROR_IF( rc, "ldap_pvt_thread_sleep" );
711 ldap_pvt_thread_create(
712 ldap_pvt_thread_t *thread,
714 void *(*start_routine)( void * ),
720 ERROR_IF( !threading_enabled, "ldap_pvt_thread_create" );
722 with_thread_info_lock({
723 rc = ldap_int_thread_create( thread, detach, start_routine, arg );
725 add_thread_info( "ldap_pvt_thread_create", thread, detach );
728 rc = ldap_int_thread_create( thread, detach, start_routine, arg );
731 ERROR( rc, "ldap_pvt_thread_create" );
734 char buf[40], buf2[40];
736 "== thr_debug: Created thread %s%s from thread %s ==\n",
737 thread_name( buf, sizeof(buf), *thread ),
738 detach ? " (detached)" : "",
739 thread_name( buf2, sizeof(buf2), ldap_pvt_thread_self() ) );
741 adjust_count( Idx_unexited_thread, +1 );
743 adjust_count( Idx_unjoined_thread, +1 );
749 ldap_pvt_thread_exit( void *retval )
751 ldap_pvt_thread_t thread;
752 ERROR_IF( !threading_enabled, "ldap_pvt_thread_exit" );
753 thread = ldap_pvt_thread_self();
756 fprintf( stderr, "== thr_debug: Exiting thread %s ==\n",
757 thread_name( buf, sizeof(buf), thread ) );
760 with_thread_info_lock({
761 ldap_debug_thread_t *t = get_thread_info(
762 &thread, "ldap_pvt_thread_exit" );
763 if( thread_info_detached( t ) )
764 remove_thread_info( t, "ldap_pvt_thread_exit" );
767 adjust_count( Idx_unexited_thread, -1 );
768 ldap_int_thread_exit( retval );
772 ldap_pvt_thread_join( ldap_pvt_thread_t thread, void **thread_return )
775 ldap_debug_thread_t *t = NULL;
776 ERROR_IF( !threading_enabled, "ldap_pvt_thread_join" );
778 char buf[40], buf2[40];
779 fprintf( stderr, "== thr_debug: Joining thread %s in thread %s ==\n",
780 thread_name( buf, sizeof(buf), thread ),
781 thread_name( buf2, sizeof(buf2), ldap_pvt_thread_self() ) );
784 with_thread_info_lock( {
785 t = get_thread_info( &thread, "ldap_pvt_thread_join" );
786 ERROR_IF( thread_info_detached( t ), "ldap_pvt_thread_join" );
788 rc = ldap_int_thread_join( thread, thread_return );
790 ERROR( rc, "ldap_pvt_thread_join" );
793 with_thread_info_lock(
794 remove_thread_info( t, "ldap_pvt_thread_join" ) );
795 adjust_count( Idx_unjoined_thread, -1 );
801 ldap_pvt_thread_kill( ldap_pvt_thread_t thread, int signo )
804 ERROR_IF( !threading_enabled, "ldap_pvt_thread_kill" );
806 char buf[40], buf2[40];
808 "== thr_debug: Killing thread %s (sig %i) from thread %s ==\n",
809 thread_name( buf, sizeof(buf), thread ), signo,
810 thread_name( buf2, sizeof(buf2), ldap_pvt_thread_self() ) );
812 rc = ldap_int_thread_kill( thread, signo );
813 ERROR_IF( rc, "ldap_pvt_thread_kill" );
818 ldap_pvt_thread_yield( void )
821 ERROR_IF( !threading_enabled, "ldap_pvt_thread_yield" );
822 rc = ldap_int_thread_yield();
823 ERROR_IF( rc, "ldap_pvt_thread_yield" );
828 ldap_pvt_thread_self( void )
830 #if 0 /* Function is used by ch_free() via slap_sl_contxt() in slapd */
831 ERROR_IF( !threading_enabled, "ldap_pvt_thread_self" );
833 return ldap_int_thread_self();
837 ldap_pvt_thread_cond_init( ldap_pvt_thread_cond_t *cond )
840 init_usage( &cond->usage, "ldap_pvt_thread_cond_init" );
841 rc = ldap_int_thread_cond_init( WRAPPED( cond ) );
843 ERROR( rc, "ldap_pvt_thread_cond_init" );
844 destroy_usage( &cond->usage );
846 adjust_count( Idx_cond, +1 );
852 ldap_pvt_thread_cond_destroy( ldap_pvt_thread_cond_t *cond )
855 check_usage( &cond->usage, "ldap_pvt_thread_cond_destroy" );
856 rc = ldap_int_thread_cond_destroy( WRAPPED( cond ) );
858 ERROR( rc, "ldap_pvt_thread_cond_destroy" );
860 destroy_usage( &cond->usage );
861 adjust_count( Idx_cond, -1 );
867 ldap_pvt_thread_cond_signal( ldap_pvt_thread_cond_t *cond )
870 check_usage( &cond->usage, "ldap_pvt_thread_cond_signal" );
871 rc = ldap_int_thread_cond_signal( WRAPPED( cond ) );
872 ERROR_IF( rc, "ldap_pvt_thread_cond_signal" );
877 ldap_pvt_thread_cond_broadcast( ldap_pvt_thread_cond_t *cond )
880 check_usage( &cond->usage, "ldap_pvt_thread_cond_broadcast" );
881 rc = ldap_int_thread_cond_broadcast( WRAPPED( cond ) );
882 ERROR_IF( rc, "ldap_pvt_thread_cond_broadcast" );
887 ldap_pvt_thread_cond_wait(
888 ldap_pvt_thread_cond_t *cond,
889 ldap_pvt_thread_mutex_t *mutex )
892 ldap_int_thread_t owner;
893 check_usage( &cond->usage, "ldap_pvt_thread_cond_wait:cond" );
894 check_usage( &mutex->usage, "ldap_pvt_thread_cond_wait:mutex" );
895 adjust_count( Idx_locked_mutex, -1 );
896 owner = GET_OWNER( mutex );
897 ASSERT_OWNER( mutex, "ldap_pvt_thread_cond_wait" );
898 RESET_OWNER( mutex );
899 rc = ldap_int_thread_cond_wait( WRAPPED( cond ), WRAPPED( mutex ) );
900 ASSERT_NO_OWNER( mutex, "ldap_pvt_thread_cond_wait" );
901 SET_OWNER( mutex, rc ? owner : ldap_int_thread_self() );
902 adjust_count( Idx_locked_mutex, +1 );
903 ERROR_IF( rc, "ldap_pvt_thread_cond_wait" );
908 ldap_pvt_thread_mutex_init( ldap_pvt_thread_mutex_t *mutex )
911 init_usage( &mutex->usage, "ldap_pvt_thread_mutex_init" );
912 rc = ldap_int_thread_mutex_init( WRAPPED( mutex ) );
914 ERROR( rc, "ldap_pvt_thread_mutex_init" );
915 destroy_usage( &mutex->usage );
917 RESET_OWNER( mutex );
918 adjust_count( Idx_mutex, +1 );
924 ldap_pvt_thread_mutex_destroy( ldap_pvt_thread_mutex_t *mutex )
927 check_usage( &mutex->usage, "ldap_pvt_thread_mutex_destroy" );
928 ASSERT_NO_OWNER( mutex, "ldap_pvt_thread_mutex_destroy" );
929 rc = ldap_int_thread_mutex_destroy( WRAPPED( mutex ) );
931 ERROR( rc, "ldap_pvt_thread_mutex_destroy" );
933 destroy_usage( &mutex->usage );
934 RESET_OWNER( mutex );
935 adjust_count( Idx_mutex, -1 );
941 ldap_pvt_thread_mutex_lock( ldap_pvt_thread_mutex_t *mutex )
944 check_usage( &mutex->usage, "ldap_pvt_thread_mutex_lock" );
945 rc = ldap_int_thread_mutex_lock( WRAPPED( mutex ) );
947 ERROR_IF( rc, "ldap_pvt_thread_mutex_lock" );
949 ASSERT_NO_OWNER( mutex, "ldap_pvt_thread_mutex_lock" );
950 SET_OWNER( mutex, ldap_int_thread_self() );
951 adjust_count( Idx_locked_mutex, +1 );
957 ldap_pvt_thread_mutex_trylock( ldap_pvt_thread_mutex_t *mutex )
960 check_usage( &mutex->usage, "ldap_pvt_thread_mutex_trylock" );
961 rc = ldap_int_thread_mutex_trylock( WRAPPED( mutex ) );
963 ASSERT_NO_OWNER( mutex, "ldap_pvt_thread_mutex_trylock" );
964 SET_OWNER( mutex, ldap_int_thread_self() );
965 adjust_count( Idx_locked_mutex, +1 );
971 ldap_pvt_thread_mutex_unlock( ldap_pvt_thread_mutex_t *mutex )
974 check_usage( &mutex->usage, "ldap_pvt_thread_mutex_unlock" );
975 ASSERT_OWNER( mutex, "ldap_pvt_thread_mutex_unlock" );
976 RESET_OWNER( mutex ); /* Breaks if this thread did not own the mutex */
977 rc = ldap_int_thread_mutex_unlock( WRAPPED( mutex ) );
979 ERROR_IF( rc, "ldap_pvt_thread_mutex_unlock" );
981 adjust_count( Idx_locked_mutex, -1 );
987 /* Wrappers for LDAP_THREAD_RDWR_IMPLEMENTATION: */
990 ldap_pvt_thread_rdwr_init( ldap_pvt_thread_rdwr_t *rwlock )
993 init_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_init" );
994 rc = ldap_int_thread_rdwr_init( WRAPPED( rwlock ) );
996 ERROR( rc, "ldap_pvt_thread_rdwr_init" );
997 destroy_usage( &rwlock->usage );
999 adjust_count( Idx_rdwr, +1 );
1005 ldap_pvt_thread_rdwr_destroy( ldap_pvt_thread_rdwr_t *rwlock )
1008 check_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_destroy" );
1009 rc = ldap_int_thread_rdwr_destroy( WRAPPED( rwlock ) );
1011 ERROR( rc, "ldap_pvt_thread_rdwr_destroy" );
1013 destroy_usage( &rwlock->usage );
1014 adjust_count( Idx_rdwr, -1 );
1020 ldap_pvt_thread_rdwr_rlock( ldap_pvt_thread_rdwr_t *rwlock )
1023 check_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_rlock" );
1024 rc = ldap_int_thread_rdwr_rlock( WRAPPED( rwlock ) );
1025 ERROR_IF( rc, "ldap_pvt_thread_rdwr_rlock" );
1030 ldap_pvt_thread_rdwr_rtrylock( ldap_pvt_thread_rdwr_t *rwlock )
1032 check_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_rtrylock" );
1033 return ldap_int_thread_rdwr_rtrylock( WRAPPED( rwlock ) );
1037 ldap_pvt_thread_rdwr_runlock( ldap_pvt_thread_rdwr_t *rwlock )
1040 check_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_runlock" );
1041 rc = ldap_int_thread_rdwr_runlock( WRAPPED( rwlock ) );
1042 ERROR_IF( rc, "ldap_pvt_thread_rdwr_runlock" );
1047 ldap_pvt_thread_rdwr_wlock( ldap_pvt_thread_rdwr_t *rwlock )
1050 check_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_wlock" );
1051 rc = ldap_int_thread_rdwr_wlock( WRAPPED( rwlock ) );
1052 ERROR_IF( rc, "ldap_pvt_thread_rdwr_wlock" );
1057 ldap_pvt_thread_rdwr_wtrylock( ldap_pvt_thread_rdwr_t *rwlock )
1059 check_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_wtrylock" );
1060 return ldap_int_thread_rdwr_wtrylock( WRAPPED( rwlock ) );
1064 ldap_pvt_thread_rdwr_wunlock( ldap_pvt_thread_rdwr_t *rwlock )
1067 check_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_wunlock" );
1068 rc = ldap_int_thread_rdwr_wunlock( WRAPPED( rwlock ) );
1069 ERROR_IF( rc, "ldap_pvt_thread_rdwr_wunlock" );
1073 #if defined(LDAP_RDWR_DEBUG) && !defined(LDAP_THREAD_HAVE_RDWR)
1076 ldap_pvt_thread_rdwr_readers( ldap_pvt_thread_rdwr_t *rwlock )
1078 check_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_readers" );
1079 return ldap_int_thread_rdwr_readers( WRAPPED( rwlock ) );
1083 ldap_pvt_thread_rdwr_writers( ldap_pvt_thread_rdwr_t *rwlock )
1085 check_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_writers" );
1086 return ldap_int_thread_rdwr_writers( WRAPPED( rwlock ) );
1090 ldap_pvt_thread_rdwr_active( ldap_pvt_thread_rdwr_t *rwlock )
1092 check_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_active" );
1093 return ldap_int_thread_rdwr_active( WRAPPED( rwlock ) );
1096 #endif /* LDAP_RDWR_DEBUG && !LDAP_THREAD_HAVE_RDWR */
1099 /* Some wrappers for LDAP_THREAD_POOL_IMPLEMENTATION: */
1100 #ifdef LDAP_THREAD_POOL_IMPLEMENTATION
1103 ldap_pvt_thread_pool_init(
1104 ldap_pvt_thread_pool_t *tpool,
1111 ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_init" );
1112 rc = ldap_int_thread_pool_init( tpool, max_threads, max_pending );
1114 ERROR( rc, "ldap_pvt_thread_pool_init" );
1116 adjust_count( Idx_tpool, +1 );
1122 ldap_pvt_thread_pool_submit(
1123 ldap_pvt_thread_pool_t *tpool,
1124 ldap_pvt_thread_start_t *start_routine, void *arg )
1127 ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_submit" );
1128 has_pool = (tpool != NULL && *tpool != NULL);
1129 rc = ldap_int_thread_pool_submit( tpool, start_routine, arg );
1131 ERROR_IF( rc, "ldap_pvt_thread_pool_submit" );
1136 ldap_pvt_thread_pool_maxthreads(
1137 ldap_pvt_thread_pool_t *tpool,
1140 ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_maxthreads" );
1141 return ldap_int_thread_pool_maxthreads( tpool, max_threads );
1145 ldap_pvt_thread_pool_backload( ldap_pvt_thread_pool_t *tpool )
1147 ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_backload" );
1148 return ldap_int_thread_pool_backload( tpool );
1152 ldap_pvt_thread_pool_destroy( ldap_pvt_thread_pool_t *tpool, int run_pending )
1155 ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_destroy" );
1156 has_pool = (tpool != NULL && *tpool != NULL);
1157 rc = ldap_int_thread_pool_destroy( tpool, run_pending );
1160 ERROR( rc, "ldap_pvt_thread_pool_destroy" );
1162 adjust_count( Idx_tpool, -1 );
1169 ldap_pvt_thread_pool_pause( ldap_pvt_thread_pool_t *tpool )
1171 ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_pause" );
1172 return ldap_int_thread_pool_pause( tpool );
1176 ldap_pvt_thread_pool_resume( ldap_pvt_thread_pool_t *tpool )
1178 ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_resume" );
1179 return ldap_int_thread_pool_resume( tpool );
1183 ldap_pvt_thread_pool_getkey(
1187 ldap_pvt_thread_pool_keyfree_t **kfree )
1189 #if 0 /* Function is used by ch_free() via slap_sl_contxt() in slapd */
1190 ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_getkey" );
1192 return ldap_int_thread_pool_getkey( xctx, key, data, kfree );
1196 ldap_pvt_thread_pool_setkey(
1200 ldap_pvt_thread_pool_keyfree_t *kfree )
1203 ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_setkey" );
1204 rc = ldap_int_thread_pool_setkey( xctx, key, data, kfree );
1205 ERROR_IF( rc, "ldap_pvt_thread_pool_setkey" );
1210 ldap_pvt_thread_pool_purgekey( void *key )
1212 ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_purgekey" );
1213 ldap_int_thread_pool_purgekey( key );
1217 ldap_pvt_thread_pool_context( void )
1219 #if 0 /* Function is used by ch_free() via slap_sl_contxt() in slapd */
1220 ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_context" );
1222 return ldap_int_thread_pool_context();
1226 ldap_pvt_thread_pool_context_reset( void *vctx )
1228 ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_context_reset" );
1229 ldap_int_thread_pool_context_reset( vctx );
1232 #endif /* LDAP_THREAD_POOL_IMPLEMENTATION */
1234 #endif /* LDAP_THREAD_DEBUG */