1 /* thr_debug.c - wrapper around the chosen thread wrapper, for debugging. */
2 /* $OpenLDAP: pkg/ldap/libraries/libldap_r/thr_debug.c,v 1.5.2.6 2008/02/11 23:26:42 kurt Exp $ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 2005-2008 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 * 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 wrap_threads
;
145 static int options_done
;
148 /* ldap_pvt_thread_initialize() called, ldap_pvt_thread_destroy() not called */
149 static int threading_enabled
;
152 /* Resource counts */
154 Idx_unexited_thread
, Idx_unjoined_thread
, Idx_locked_mutex
,
155 Idx_mutex
, Idx_cond
, Idx_rdwr
, Idx_tpool
, Idx_max
157 static int resource_counts
[Idx_max
];
158 static const char *const resource_names
[] = {
159 "unexited threads", "unjoined threads", "locked mutexes",
160 "mutexes", "conds", "rdwrs", "thread pools"
162 static ldap_int_thread_mutex_t resource_mutexes
[Idx_max
];
165 /* Hide pointers from malloc debuggers. */
166 #define SCRAMBLE(ptr) (~(LDAP_UINTPTR_T) (ptr))
167 #define UNSCRAMBLE_usagep(num) ((ldap_debug_usage_info_t *) ~(num))
168 #define UNSCRAMBLE_dummyp(num) ((unsigned char *) ~(num))
171 #define WARN(var, msg) (warn (__FILE__, __LINE__, (msg), #var, (var)))
172 #define WARN_IF(rc, msg) {if (rc) warn (__FILE__, __LINE__, (msg), #rc, (rc));}
174 #define ERROR(var, msg) { \
176 errmsg(__FILE__, __LINE__, (msg), #var, (var)); \
177 if( !noabort ) abort(); \
181 #define ERROR_IF(rc, msg) { \
185 errmsg(__FILE__, __LINE__, (msg), #rc, rc_); \
186 if( !noabort ) abort(); \
191 #ifdef LDAP_THREAD_DEBUG_WRAP
192 #define MEMERROR_IF(rc, msg, mem_act) { \
196 errmsg(__FILE__, __LINE__, (msg), #rc, rc_); \
197 if( wraptype != Wrap_noalloc ) { mem_act; } \
198 if( !noabort ) abort(); \
202 #endif /* LDAP_THREAD_DEBUG_WRAP */
206 warn( const char *file
, int line
, const char *msg
, const char *var
, int val
)
209 (strpbrk( var
, "!=" )
210 ? "%s:%d: %s warning: %s\n"
211 : "%s:%d: %s warning: %s is %d\n"),
212 file
, line
, msg
, var
, val
);
217 errmsg( const char *file
, int line
, const char *msg
, const char *var
, int val
)
220 (strpbrk( var
, "!=" )
221 ? "%s:%d: %s error: %s\n"
222 : "%s:%d: %s error: %s is %d\n"),
223 file
, line
, msg
, var
, val
);
227 count_resource_leaks( void )
231 if( count
== Count_yes
) {
232 count
= Count_reported
;
233 #if 0 /* Could break if there are still threads after atexit */
234 for( i
= j
= 0; i
< Idx_max
; i
++ )
235 j
|= ldap_int_thread_mutex_destroy( &resource_mutexes
[i
] );
236 WARN_IF( j
, "ldap_debug_thread_destroy:mutexes" );
238 for( i
= j
= 0; i
< Idx_max
; i
++ )
239 if( resource_counts
[i
] )
240 j
+= sprintf( errbuf
+ j
, ", %d %s",
241 resource_counts
[i
], resource_names
[i
] );
243 fprintf( stderr
, "== thr_debug: Leaked%s. ==\n", errbuf
+ 1 );
250 static const struct option_info_s
{
254 { "off", &nodebug
, 1 },
255 { "noabort", &noabort
, 1 },
256 { "noerror", &noerror
, 1 },
257 { "nocount", &count
, Count_no
},
258 { "nosync", &nosync
, 1 },
259 #if LDAP_THREAD_DEBUG_THREAD_ID +0
260 { "threadID", &threadID
, 1 },
262 #ifdef LDAP_THREAD_DEBUG_WRAP
263 { "nomem", &nomem
, 1 },
264 { "noreinit", &noreinit
, 1 },
265 { "noalloc", &wraptype
, Wrap_noalloc
},
266 { "alloc", &wraptype
, Wrap_alloc
},
267 { "adjptr", &wraptype
, Wrap_adjptr
},
268 { "scramble", &wraptype
, Wrap_scramble
},
270 { "tracethreads", &tracethreads
, 1 },
273 const char *s
= getenv( "LDAP_THREAD_DEBUG" );
275 while( *(s
+= strspn( s
, ", \t\r\n" )) != '\0' ) {
276 size_t optlen
= strcspn( s
, ", \t\r\n" );
277 const struct option_info_s
*oi
= option_info
;
279 (strncasecmp( oi
->name
, s
, optlen
) || oi
->name
[optlen
]) )
285 "== thr_debug: Unknown $%s option '%.*s' ==\n",
286 "LDAP_THREAD_DEBUG", (int) optlen
, s
);
292 nosync
= noerror
= 1;
298 #if LDAP_THREAD_DEBUG_THREAD_ID +0
302 #ifdef LDAP_THREAD_DEBUG_WRAP
306 static const ldap_debug_usage_info_t usage
;
307 if( sizeof(LDAP_UINTPTR_T
) < sizeof(unsigned char *)
308 || sizeof(LDAP_UINTPTR_T
) < sizeof(ldap_debug_usage_info_t
*)
309 || UNSCRAMBLE_usagep( SCRAMBLE( &usage
) ) != &usage
310 || UNSCRAMBLE_dummyp( SCRAMBLE( (unsigned char *) 0 ) ) )
312 fputs( "== thr_debug: Memory checks unsupported, "
313 "adding nomem to $LDAP_THREAD_DEBUG ==\n", stderr
);
319 wraptype
= Wrap_noalloc
;
321 unwrap_offset
= -(wrap_offset
= (wraptype
== Wrap_adjptr
));
323 wrap_threads
= (tracethreads
|| threadID
|| count
);
328 #ifndef LDAP_THREAD_DEBUG_WRAP
330 #define WRAPPED(ptr) (ptr)
331 #define GET_OWNER(ptr) 0
332 #define SET_OWNER(ptr, thread) ((void) 0)
333 #define RESET_OWNER(ptr) ((void) 0)
334 #define ASSERT_OWNER(ptr, msg) ((void) 0)
335 #define ASSERT_NO_OWNER(ptr, msg) ((void) 0)
337 #define init_usage(ptr, msg) ((void) 0)
338 #define check_usage(ptr, msg) ((void) 0)
339 #define destroy_usage(ptr) ((void) 0)
341 #else /* LDAP_THREAD_DEBUG_WRAP */
343 /* Specialize this if the initializer is not appropriate. */
344 /* The ASSERT_NO_OWNER() definition may also need an override. */
345 #ifndef LDAP_DEBUG_THREAD_NONE
346 #define LDAP_DEBUG_THREAD_NONE { -1 } /* "no thread" ldap_int_thread_t value */
349 static const ldap_int_thread_t ldap_debug_thread_none
= LDAP_DEBUG_THREAD_NONE
;
351 #define THREAD_MUTEX_OWNER(mutex) \
352 ldap_int_thread_equal( (mutex)->owner, ldap_int_thread_self() )
355 ldap_debug_thread_assert_mutex_owner(
359 ldap_pvt_thread_mutex_t
*mutex
)
361 if( !(noerror
|| THREAD_MUTEX_OWNER( mutex
)) ) {
362 errmsg( file
, line
, msg
, "ASSERT_MUTEX_OWNER", 0 );
363 if( !noabort
) abort();
367 #define WRAPPED(ptr) (&(ptr)->wrapped)
368 #define GET_OWNER(ptr) ((ptr)->owner)
369 #define SET_OWNER(ptr, thread) ((ptr)->owner = (thread))
370 #define RESET_OWNER(ptr) ((ptr)->owner = ldap_debug_thread_none)
371 #define ASSERT_OWNER(ptr, msg) ERROR_IF( !THREAD_MUTEX_OWNER( ptr ), msg )
372 #ifndef ASSERT_NO_OWNER
373 #define ASSERT_NO_OWNER(ptr, msg) ERROR_IF( \
374 !ldap_int_thread_equal( (ptr)->owner, ldap_debug_thread_none ), msg )
377 /* Try to provoke memory access error (for malloc debuggers) */
378 #define PEEK(mem) {if (-*(volatile const unsigned char *)(mem)) debug_noop();}
380 static void debug_noop( void );
381 static int debug_already_initialized( const ldap_debug_usage_info_t
*usage
);
383 /* Name used for clearer error message */
384 #define IS_COPY_OR_MOVED(usage) ((usage)->self != SCRAMBLE( usage ))
386 #define DUMMY_ADDR(usage) \
387 (wraptype == Wrap_scramble \
388 ? UNSCRAMBLE_dummyp( (usage)->mem.num ) \
389 : (usage)->mem.ptr + unwrap_offset)
391 /* Mark resource as initialized */
393 init_usage( ldap_debug_usage_info_t
*usage
, const char *msg
)
399 MEMERROR_IF( debug_already_initialized( usage
), msg
, {
400 /* Provoke malloc debuggers */
401 unsigned char *dummy
= DUMMY_ADDR( usage
);
407 if( wraptype
!= Wrap_noalloc
) {
408 unsigned char *dummy
= malloc( 1 );
409 assert( dummy
!= NULL
);
410 if( wraptype
== Wrap_scramble
) {
411 usage
->mem
.num
= SCRAMBLE( dummy
);
412 /* Verify that ptr<->integer casts work on this host */
413 assert( UNSCRAMBLE_dummyp( usage
->mem
.num
) == dummy
);
415 usage
->mem
.ptr
= dummy
+ wrap_offset
;
419 /* Unused, but set for readability in debugger */
420 usage
->mem
.ptr
= NULL
;
422 usage
->self
= SCRAMBLE( usage
); /* If nomem, only for debugger */
423 usage
->magic
= ldap_debug_magic
;
424 usage
->state
= ldap_debug_state_inited
;
427 /* Check that resource is initialized and not copied/realloced */
429 check_usage( const ldap_debug_usage_info_t
*usage
, const char *msg
)
431 enum { Is_destroyed
= 1 }; /* Name used for clearer error message */
433 if( usage
->magic
!= ldap_debug_magic
) {
434 ERROR( usage
->magic
, msg
);
437 switch( usage
->state
) {
438 case ldap_debug_state_destroyed
:
439 MEMERROR_IF( Is_destroyed
, msg
, {
440 PEEK( DUMMY_ADDR( usage
) );
444 ERROR( usage
->state
, msg
);
446 case ldap_debug_state_inited
:
448 MEMERROR_IF( IS_COPY_OR_MOVED( usage
), msg
, {
449 PEEK( DUMMY_ADDR( usage
) );
450 PEEK( UNSCRAMBLE_usagep( usage
->self
) );
457 /* Mark resource as destroyed. */
458 /* Does not check for errors, call check_usage()/init_usage() first. */
460 destroy_usage( ldap_debug_usage_info_t
*usage
)
462 if( usage
->state
== ldap_debug_state_inited
) {
463 if( wraptype
!= Wrap_noalloc
) {
464 free( DUMMY_ADDR( usage
) );
465 /* Do not reset the DUMMY_ADDR, leave it for malloc debuggers
466 * in case the resource is used after it is freed. */
468 usage
->state
= ldap_debug_state_destroyed
;
472 /* Define these after they are used, so they are hopefully not inlined */
480 * Valid programs access uninitialized memory here unless "noreinit".
482 * Returns true if the resource is initialized and not copied/realloced.
485 debug_already_initialized( const ldap_debug_usage_info_t
*usage
)
488 * 'ret' keeps the Valgrind warning "Conditional jump or move
489 * depends on uninitialised value(s)" _inside_ this function.
491 volatile int ret
= 0;
492 if( usage
->state
== ldap_debug_state_inited
)
493 if( !IS_COPY_OR_MOVED( usage
) )
494 if( usage
->magic
== ldap_debug_magic
)
499 #endif /* LDAP_THREAD_DEBUG_WRAP */
502 #if !(LDAP_THREAD_DEBUG_THREAD_ID +0)
504 typedef void ldap_debug_thread_t
;
505 #define init_thread_info() {}
506 #define with_thread_info_lock(statements) { statements; }
507 #define thread_info_detached(t) 0
508 #define add_thread_info(msg, thr, det) ((void) 0)
509 #define remove_thread_info(tinfo, msg) ((void) 0)
510 #define get_thread_info(thread, msg) NULL
512 #else /* LDAP_THREAD_DEBUG_THREAD_ID */
515 * Thread ID tracking. Currently acieves little.
516 * Should be either expanded or deleted.
520 * Array of threads. Used instead of making ldap_pvt_thread_t a wrapper
521 * around ldap_int_thread_t, which would slow down ldap_pvt_thread_self().
524 ldap_pvt_thread_t wrapped
;
525 ldap_debug_usage_info_t usage
;
528 } ldap_debug_thread_t
;
530 static ldap_debug_thread_t
**thread_info
;
531 static unsigned int thread_info_size
, thread_info_used
;
532 static ldap_int_thread_mutex_t thread_info_mutex
;
534 #define init_thread_info() { \
536 int mutex_init_rc = ldap_int_thread_mutex_init( &thread_info_mutex ); \
537 assert( mutex_init_rc == 0 ); \
541 #define with_thread_info_lock(statements) { \
542 int rc_wtl_ = ldap_int_thread_mutex_lock( &thread_info_mutex ); \
543 assert( rc_wtl_ == 0 ); \
545 rc_wtl_ = ldap_int_thread_mutex_unlock( &thread_info_mutex ); \
546 assert( rc_wtl_ == 0 ); \
549 #define thread_info_detached(t) ((t)->detached)
554 const ldap_pvt_thread_t
*thread
,
557 ldap_debug_thread_t
*t
;
558 if( thread_info_used
>= thread_info_size
) {
559 unsigned int more
= thread_info_size
+ 8;
560 unsigned int new_size
= thread_info_size
+ more
;
561 t
= calloc( more
, sizeof(ldap_debug_thread_t
) );
563 thread_info
= realloc( thread_info
, new_size
* sizeof(*thread_info
) );
564 assert( thread_info
!= NULL
);
565 while( thread_info_size
< new_size
) {
566 t
->idx
= thread_info_size
;
567 thread_info
[thread_info_size
++] = t
++;
570 t
= thread_info
[thread_info_used
];
571 init_usage( &t
->usage
, msg
);
572 t
->wrapped
= *thread
;
573 t
->detached
= detached
;
578 remove_thread_info( ldap_debug_thread_t
*t
, const char *msg
)
580 ldap_debug_thread_t
*last
;
582 check_usage( &t
->usage
, msg
);
583 destroy_usage( &t
->usage
);
585 assert( thread_info
[idx
] == t
);
586 last
= thread_info
[--thread_info_used
];
587 assert( last
->idx
== thread_info_used
);
588 (thread_info
[idx
] = last
)->idx
= idx
;
589 (thread_info
[thread_info_used
] = t
)->idx
= thread_info_used
;
592 static ldap_debug_thread_t
*
593 get_thread_info( ldap_pvt_thread_t thread
, const char *msg
)
596 ldap_debug_thread_t
*t
;
597 for( i
= 0; i
< thread_info_used
; i
++ ) {
598 if( ldap_pvt_thread_equal( thread
, thread_info
[i
]->wrapped
) )
601 ERROR_IF( i
== thread_info_used
, msg
);
603 check_usage( &t
->usage
, msg
);
607 #endif /* LDAP_THREAD_DEBUG_THREAD_ID */
611 thread_name( char *buf
, int bufsize
, ldap_pvt_thread_t thread
)
615 if( bufsize
> 2*sizeof(thread
) )
616 bufsize
= 2*sizeof(thread
);
617 for( i
= 0; i
< bufsize
; i
+= 2 )
618 snprintf( buf
+i
, 3, "%02x", ((unsigned char *)&thread
)[i
/2] );
623 /* Add <adjust> (+/-1) to resource count <which> unless "nocount". */
625 adjust_count( int which
, int adjust
)
632 rc
= ldap_int_thread_mutex_lock( &resource_mutexes
[which
] );
634 resource_counts
[which
] += adjust
;
635 rc
= ldap_int_thread_mutex_unlock( &resource_mutexes
[which
] );
639 fputs( "== thr_debug: More thread activity after exit ==\n", stderr
);
640 count
= Count_reported_more
;
642 case Count_reported_more
:
643 /* Not used, but result might be inspected with debugger */
644 /* (Hopefully threading is disabled by now...) */
645 resource_counts
[which
] += adjust
;
651 /* Wrappers for LDAP_THREAD_IMPLEMENTATION: */
653 /* Used instead of ldap_int_thread_initialize by ldap_pvt_thread_initialize */
655 ldap_debug_thread_initialize( void )
660 ERROR_IF( threading_enabled
, "ldap_debug_thread_initialize" );
661 threading_enabled
= 1;
662 rc
= ldap_int_thread_initialize();
664 ERROR( rc
, "ldap_debug_thread_initialize:threads" );
665 threading_enabled
= 0;
668 if( count
!= Count_no
) {
669 for( i
= rc2
= 0; i
< Idx_max
; i
++ )
670 rc2
|= ldap_int_thread_mutex_init( &resource_mutexes
[i
] );
672 /* FIXME: Only for static libldap_r as in init.c? If so, why? */
673 atexit( count_resource_leaks
);
679 /* Used instead of ldap_int_thread_destroy by ldap_pvt_thread_destroy */
681 ldap_debug_thread_destroy( void )
684 ERROR_IF( !threading_enabled
, "ldap_debug_thread_destroy" );
685 /* sleep(1) -- need to wait for thread pool to finish? */
686 rc
= ldap_int_thread_destroy();
688 ERROR( rc
, "ldap_debug_thread_destroy:threads" );
690 threading_enabled
= 0;
696 ldap_pvt_thread_set_concurrency( int n
)
699 ERROR_IF( !threading_enabled
, "ldap_pvt_thread_set_concurrency" );
700 rc
= ldap_int_thread_set_concurrency( n
);
701 ERROR_IF( rc
, "ldap_pvt_thread_set_concurrency" );
706 ldap_pvt_thread_get_concurrency( void )
709 ERROR_IF( !threading_enabled
, "ldap_pvt_thread_get_concurrency" );
710 rc
= ldap_int_thread_get_concurrency();
711 ERROR_IF( rc
, "ldap_pvt_thread_get_concurrency" );
716 ldap_pvt_thread_sleep( unsigned int interval
)
719 ERROR_IF( !threading_enabled
, "ldap_pvt_thread_sleep" );
720 rc
= ldap_int_thread_sleep( interval
);
721 ERROR_IF( rc
, "ldap_pvt_thread_sleep" );
726 thread_exiting( const char *how
, const char *msg
)
728 ldap_pvt_thread_t thread
;
729 #if 0 /* Detached threads may exit after ldap_debug_thread_destroy(). */
730 ERROR_IF( !threading_enabled
, msg
);
732 thread
= ldap_pvt_thread_self();
735 fprintf( stderr
, "== thr_debug: %s thread %s ==\n",
736 how
, thread_name( buf
, sizeof(buf
), thread
) );
739 with_thread_info_lock({
740 ldap_debug_thread_t
*t
= get_thread_info( thread
, msg
);
741 if( thread_info_detached( t
) )
742 remove_thread_info( t
, msg
);
745 adjust_count( Idx_unexited_thread
, -1 );
749 ldap_pvt_thread_exit( void *retval
)
751 thread_exiting( "Exiting", "ldap_pvt_thread_exit" );
752 ldap_int_thread_exit( retval
);
756 void *(*start_routine
)( void * );
758 } ldap_debug_thread_call_t
;
761 ldap_debug_thread_wrapper( void *arg
)
764 ldap_debug_thread_call_t call
= *(ldap_debug_thread_call_t
*)arg
;
766 ret
= call
.start_routine( call
.arg
);
767 thread_exiting( "Returning from", "ldap_debug_thread_wrapper" );
772 ldap_pvt_thread_create(
773 ldap_pvt_thread_t
*thread
,
775 void *(*start_routine
)( void * ),
781 ERROR_IF( !threading_enabled
, "ldap_pvt_thread_create" );
783 ldap_debug_thread_call_t
*call
= malloc(
784 sizeof( ldap_debug_thread_call_t
) );
785 assert( call
!= NULL
);
786 call
->start_routine
= start_routine
;
788 start_routine
= ldap_debug_thread_wrapper
;
792 with_thread_info_lock({
793 rc
= ldap_int_thread_create( thread
, detach
, start_routine
, arg
);
795 add_thread_info( "ldap_pvt_thread_create", thread
, detach
);
798 rc
= ldap_int_thread_create( thread
, detach
, start_routine
, arg
);
801 ERROR( rc
, "ldap_pvt_thread_create" );
806 char buf
[40], buf2
[40];
808 "== thr_debug: Created thread %s%s from thread %s ==\n",
809 thread_name( buf
, sizeof(buf
), *thread
),
810 detach
? " (detached)" : "",
811 thread_name( buf2
, sizeof(buf2
), ldap_pvt_thread_self() ) );
813 adjust_count( Idx_unexited_thread
, +1 );
815 adjust_count( Idx_unjoined_thread
, +1 );
821 ldap_pvt_thread_join( ldap_pvt_thread_t thread
, void **thread_return
)
824 ldap_debug_thread_t
*t
= NULL
;
825 ERROR_IF( !threading_enabled
, "ldap_pvt_thread_join" );
827 char buf
[40], buf2
[40];
828 fprintf( stderr
, "== thr_debug: Joining thread %s in thread %s ==\n",
829 thread_name( buf
, sizeof(buf
), thread
),
830 thread_name( buf2
, sizeof(buf2
), ldap_pvt_thread_self() ) );
833 with_thread_info_lock( {
834 t
= get_thread_info( thread
, "ldap_pvt_thread_join" );
835 ERROR_IF( thread_info_detached( t
), "ldap_pvt_thread_join" );
837 rc
= ldap_int_thread_join( thread
, thread_return
);
839 ERROR( rc
, "ldap_pvt_thread_join" );
842 with_thread_info_lock(
843 remove_thread_info( t
, "ldap_pvt_thread_join" ) );
844 adjust_count( Idx_unjoined_thread
, -1 );
850 ldap_pvt_thread_kill( ldap_pvt_thread_t thread
, int signo
)
853 ERROR_IF( !threading_enabled
, "ldap_pvt_thread_kill" );
855 char buf
[40], buf2
[40];
857 "== thr_debug: Killing thread %s (sig %i) from thread %s ==\n",
858 thread_name( buf
, sizeof(buf
), thread
), signo
,
859 thread_name( buf2
, sizeof(buf2
), ldap_pvt_thread_self() ) );
861 rc
= ldap_int_thread_kill( thread
, signo
);
862 ERROR_IF( rc
, "ldap_pvt_thread_kill" );
867 ldap_pvt_thread_yield( void )
870 ERROR_IF( !threading_enabled
, "ldap_pvt_thread_yield" );
871 rc
= ldap_int_thread_yield();
872 ERROR_IF( rc
, "ldap_pvt_thread_yield" );
877 ldap_pvt_thread_self( void )
879 #if 0 /* Function is used by ch_free() via slap_sl_contxt() in slapd */
880 ERROR_IF( !threading_enabled
, "ldap_pvt_thread_self" );
882 return ldap_int_thread_self();
886 ldap_pvt_thread_cond_init( ldap_pvt_thread_cond_t
*cond
)
889 init_usage( &cond
->usage
, "ldap_pvt_thread_cond_init" );
890 rc
= ldap_int_thread_cond_init( WRAPPED( cond
) );
892 ERROR( rc
, "ldap_pvt_thread_cond_init" );
893 destroy_usage( &cond
->usage
);
895 adjust_count( Idx_cond
, +1 );
901 ldap_pvt_thread_cond_destroy( ldap_pvt_thread_cond_t
*cond
)
904 check_usage( &cond
->usage
, "ldap_pvt_thread_cond_destroy" );
905 rc
= ldap_int_thread_cond_destroy( WRAPPED( cond
) );
907 ERROR( rc
, "ldap_pvt_thread_cond_destroy" );
909 destroy_usage( &cond
->usage
);
910 adjust_count( Idx_cond
, -1 );
916 ldap_pvt_thread_cond_signal( ldap_pvt_thread_cond_t
*cond
)
919 check_usage( &cond
->usage
, "ldap_pvt_thread_cond_signal" );
920 rc
= ldap_int_thread_cond_signal( WRAPPED( cond
) );
921 ERROR_IF( rc
, "ldap_pvt_thread_cond_signal" );
926 ldap_pvt_thread_cond_broadcast( ldap_pvt_thread_cond_t
*cond
)
929 check_usage( &cond
->usage
, "ldap_pvt_thread_cond_broadcast" );
930 rc
= ldap_int_thread_cond_broadcast( WRAPPED( cond
) );
931 ERROR_IF( rc
, "ldap_pvt_thread_cond_broadcast" );
936 ldap_pvt_thread_cond_wait(
937 ldap_pvt_thread_cond_t
*cond
,
938 ldap_pvt_thread_mutex_t
*mutex
)
941 ldap_int_thread_t owner
;
942 check_usage( &cond
->usage
, "ldap_pvt_thread_cond_wait:cond" );
943 check_usage( &mutex
->usage
, "ldap_pvt_thread_cond_wait:mutex" );
944 adjust_count( Idx_locked_mutex
, -1 );
945 owner
= GET_OWNER( mutex
);
946 ASSERT_OWNER( mutex
, "ldap_pvt_thread_cond_wait" );
947 RESET_OWNER( mutex
);
948 rc
= ldap_int_thread_cond_wait( WRAPPED( cond
), WRAPPED( mutex
) );
949 ASSERT_NO_OWNER( mutex
, "ldap_pvt_thread_cond_wait" );
950 SET_OWNER( mutex
, rc
? owner
: ldap_int_thread_self() );
951 adjust_count( Idx_locked_mutex
, +1 );
952 ERROR_IF( rc
, "ldap_pvt_thread_cond_wait" );
957 ldap_pvt_thread_mutex_init( ldap_pvt_thread_mutex_t
*mutex
)
960 init_usage( &mutex
->usage
, "ldap_pvt_thread_mutex_init" );
961 rc
= ldap_int_thread_mutex_init( WRAPPED( mutex
) );
963 ERROR( rc
, "ldap_pvt_thread_mutex_init" );
964 destroy_usage( &mutex
->usage
);
966 RESET_OWNER( mutex
);
967 adjust_count( Idx_mutex
, +1 );
973 ldap_pvt_thread_mutex_destroy( ldap_pvt_thread_mutex_t
*mutex
)
976 check_usage( &mutex
->usage
, "ldap_pvt_thread_mutex_destroy" );
977 ASSERT_NO_OWNER( mutex
, "ldap_pvt_thread_mutex_destroy" );
978 rc
= ldap_int_thread_mutex_destroy( WRAPPED( mutex
) );
980 ERROR( rc
, "ldap_pvt_thread_mutex_destroy" );
982 destroy_usage( &mutex
->usage
);
983 RESET_OWNER( mutex
);
984 adjust_count( Idx_mutex
, -1 );
990 ldap_pvt_thread_mutex_lock( ldap_pvt_thread_mutex_t
*mutex
)
993 check_usage( &mutex
->usage
, "ldap_pvt_thread_mutex_lock" );
994 rc
= ldap_int_thread_mutex_lock( WRAPPED( mutex
) );
996 ERROR_IF( rc
, "ldap_pvt_thread_mutex_lock" );
998 ASSERT_NO_OWNER( mutex
, "ldap_pvt_thread_mutex_lock" );
999 SET_OWNER( mutex
, ldap_int_thread_self() );
1000 adjust_count( Idx_locked_mutex
, +1 );
1006 ldap_pvt_thread_mutex_trylock( ldap_pvt_thread_mutex_t
*mutex
)
1009 check_usage( &mutex
->usage
, "ldap_pvt_thread_mutex_trylock" );
1010 rc
= ldap_int_thread_mutex_trylock( WRAPPED( mutex
) );
1012 ASSERT_NO_OWNER( mutex
, "ldap_pvt_thread_mutex_trylock" );
1013 SET_OWNER( mutex
, ldap_int_thread_self() );
1014 adjust_count( Idx_locked_mutex
, +1 );
1020 ldap_pvt_thread_mutex_unlock( ldap_pvt_thread_mutex_t
*mutex
)
1023 check_usage( &mutex
->usage
, "ldap_pvt_thread_mutex_unlock" );
1024 ASSERT_OWNER( mutex
, "ldap_pvt_thread_mutex_unlock" );
1025 RESET_OWNER( mutex
); /* Breaks if this thread did not own the mutex */
1026 rc
= ldap_int_thread_mutex_unlock( WRAPPED( mutex
) );
1028 ERROR_IF( rc
, "ldap_pvt_thread_mutex_unlock" );
1030 adjust_count( Idx_locked_mutex
, -1 );
1036 /* Wrappers for LDAP_THREAD_RDWR_IMPLEMENTATION: */
1039 ldap_pvt_thread_rdwr_init( ldap_pvt_thread_rdwr_t
*rwlock
)
1042 init_usage( &rwlock
->usage
, "ldap_pvt_thread_rdwr_init" );
1043 rc
= ldap_int_thread_rdwr_init( WRAPPED( rwlock
) );
1045 ERROR( rc
, "ldap_pvt_thread_rdwr_init" );
1046 destroy_usage( &rwlock
->usage
);
1048 adjust_count( Idx_rdwr
, +1 );
1054 ldap_pvt_thread_rdwr_destroy( ldap_pvt_thread_rdwr_t
*rwlock
)
1057 check_usage( &rwlock
->usage
, "ldap_pvt_thread_rdwr_destroy" );
1058 rc
= ldap_int_thread_rdwr_destroy( WRAPPED( rwlock
) );
1060 ERROR( rc
, "ldap_pvt_thread_rdwr_destroy" );
1062 destroy_usage( &rwlock
->usage
);
1063 adjust_count( Idx_rdwr
, -1 );
1069 ldap_pvt_thread_rdwr_rlock( ldap_pvt_thread_rdwr_t
*rwlock
)
1072 check_usage( &rwlock
->usage
, "ldap_pvt_thread_rdwr_rlock" );
1073 rc
= ldap_int_thread_rdwr_rlock( WRAPPED( rwlock
) );
1074 ERROR_IF( rc
, "ldap_pvt_thread_rdwr_rlock" );
1079 ldap_pvt_thread_rdwr_rtrylock( ldap_pvt_thread_rdwr_t
*rwlock
)
1081 check_usage( &rwlock
->usage
, "ldap_pvt_thread_rdwr_rtrylock" );
1082 return ldap_int_thread_rdwr_rtrylock( WRAPPED( rwlock
) );
1086 ldap_pvt_thread_rdwr_runlock( ldap_pvt_thread_rdwr_t
*rwlock
)
1089 check_usage( &rwlock
->usage
, "ldap_pvt_thread_rdwr_runlock" );
1090 rc
= ldap_int_thread_rdwr_runlock( WRAPPED( rwlock
) );
1091 ERROR_IF( rc
, "ldap_pvt_thread_rdwr_runlock" );
1096 ldap_pvt_thread_rdwr_wlock( ldap_pvt_thread_rdwr_t
*rwlock
)
1099 check_usage( &rwlock
->usage
, "ldap_pvt_thread_rdwr_wlock" );
1100 rc
= ldap_int_thread_rdwr_wlock( WRAPPED( rwlock
) );
1101 ERROR_IF( rc
, "ldap_pvt_thread_rdwr_wlock" );
1106 ldap_pvt_thread_rdwr_wtrylock( ldap_pvt_thread_rdwr_t
*rwlock
)
1108 check_usage( &rwlock
->usage
, "ldap_pvt_thread_rdwr_wtrylock" );
1109 return ldap_int_thread_rdwr_wtrylock( WRAPPED( rwlock
) );
1113 ldap_pvt_thread_rdwr_wunlock( ldap_pvt_thread_rdwr_t
*rwlock
)
1116 check_usage( &rwlock
->usage
, "ldap_pvt_thread_rdwr_wunlock" );
1117 rc
= ldap_int_thread_rdwr_wunlock( WRAPPED( rwlock
) );
1118 ERROR_IF( rc
, "ldap_pvt_thread_rdwr_wunlock" );
1122 #if defined(LDAP_RDWR_DEBUG) && !defined(LDAP_THREAD_HAVE_RDWR)
1125 ldap_pvt_thread_rdwr_readers( ldap_pvt_thread_rdwr_t
*rwlock
)
1127 check_usage( &rwlock
->usage
, "ldap_pvt_thread_rdwr_readers" );
1128 return ldap_int_thread_rdwr_readers( WRAPPED( rwlock
) );
1132 ldap_pvt_thread_rdwr_writers( ldap_pvt_thread_rdwr_t
*rwlock
)
1134 check_usage( &rwlock
->usage
, "ldap_pvt_thread_rdwr_writers" );
1135 return ldap_int_thread_rdwr_writers( WRAPPED( rwlock
) );
1139 ldap_pvt_thread_rdwr_active( ldap_pvt_thread_rdwr_t
*rwlock
)
1141 check_usage( &rwlock
->usage
, "ldap_pvt_thread_rdwr_active" );
1142 return ldap_int_thread_rdwr_active( WRAPPED( rwlock
) );
1145 #endif /* LDAP_RDWR_DEBUG && !LDAP_THREAD_HAVE_RDWR */
1148 /* Some wrappers for LDAP_THREAD_POOL_IMPLEMENTATION: */
1149 #ifdef LDAP_THREAD_POOL_IMPLEMENTATION
1152 ldap_pvt_thread_pool_init(
1153 ldap_pvt_thread_pool_t
*tpool
,
1160 ERROR_IF( !threading_enabled
, "ldap_pvt_thread_pool_init" );
1161 rc
= ldap_int_thread_pool_init( tpool
, max_threads
, max_pending
);
1163 ERROR( rc
, "ldap_pvt_thread_pool_init" );
1165 adjust_count( Idx_tpool
, +1 );
1171 ldap_pvt_thread_pool_submit(
1172 ldap_pvt_thread_pool_t
*tpool
,
1173 ldap_pvt_thread_start_t
*start_routine
, void *arg
)
1176 ERROR_IF( !threading_enabled
, "ldap_pvt_thread_pool_submit" );
1177 has_pool
= (tpool
&& *tpool
);
1178 rc
= ldap_int_thread_pool_submit( tpool
, start_routine
, arg
);
1180 ERROR_IF( rc
, "ldap_pvt_thread_pool_submit" );
1185 ldap_pvt_thread_pool_maxthreads(
1186 ldap_pvt_thread_pool_t
*tpool
,
1189 ERROR_IF( !threading_enabled
, "ldap_pvt_thread_pool_maxthreads" );
1190 return ldap_int_thread_pool_maxthreads( tpool
, max_threads
);
1194 ldap_pvt_thread_pool_backload( ldap_pvt_thread_pool_t
*tpool
)
1196 ERROR_IF( !threading_enabled
, "ldap_pvt_thread_pool_backload" );
1197 return ldap_int_thread_pool_backload( tpool
);
1201 ldap_pvt_thread_pool_destroy( ldap_pvt_thread_pool_t
*tpool
, int run_pending
)
1204 ERROR_IF( !threading_enabled
, "ldap_pvt_thread_pool_destroy" );
1205 has_pool
= (tpool
&& *tpool
);
1206 rc
= ldap_int_thread_pool_destroy( tpool
, run_pending
);
1209 ERROR( rc
, "ldap_pvt_thread_pool_destroy" );
1211 adjust_count( Idx_tpool
, -1 );
1218 ldap_pvt_thread_pool_pause( ldap_pvt_thread_pool_t
*tpool
)
1220 ERROR_IF( !threading_enabled
, "ldap_pvt_thread_pool_pause" );
1221 return ldap_int_thread_pool_pause( tpool
);
1225 ldap_pvt_thread_pool_resume( ldap_pvt_thread_pool_t
*tpool
)
1227 ERROR_IF( !threading_enabled
, "ldap_pvt_thread_pool_resume" );
1228 return ldap_int_thread_pool_resume( tpool
);
1232 ldap_pvt_thread_pool_getkey(
1236 ldap_pvt_thread_pool_keyfree_t
**kfree
)
1238 #if 0 /* Function is used by ch_free() via slap_sl_contxt() in slapd */
1239 ERROR_IF( !threading_enabled
, "ldap_pvt_thread_pool_getkey" );
1241 return ldap_int_thread_pool_getkey( xctx
, key
, data
, kfree
);
1245 ldap_pvt_thread_pool_setkey(
1249 ldap_pvt_thread_pool_keyfree_t
*kfree
,
1251 ldap_pvt_thread_pool_keyfree_t
**oldkfreep
)
1254 ERROR_IF( !threading_enabled
, "ldap_pvt_thread_pool_setkey" );
1255 rc
= ldap_int_thread_pool_setkey(
1256 xctx
, key
, data
, kfree
, olddatap
, oldkfreep
);
1257 ERROR_IF( rc
, "ldap_pvt_thread_pool_setkey" );
1262 ldap_pvt_thread_pool_purgekey( void *key
)
1264 ERROR_IF( !threading_enabled
, "ldap_pvt_thread_pool_purgekey" );
1265 ldap_int_thread_pool_purgekey( key
);
1269 ldap_pvt_thread_pool_context( void )
1271 #if 0 /* Function is used by ch_free() via slap_sl_contxt() in slapd */
1272 ERROR_IF( !threading_enabled
, "ldap_pvt_thread_pool_context" );
1274 return ldap_int_thread_pool_context();
1278 ldap_pvt_thread_pool_context_reset( void *vctx
)
1280 ERROR_IF( !threading_enabled
, "ldap_pvt_thread_pool_context_reset" );
1281 ldap_int_thread_pool_context_reset( vctx
);
1284 #endif /* LDAP_THREAD_POOL_IMPLEMENTATION */
1286 #endif /* LDAP_THREAD_DEBUG */