1 /*        $NetBSD: thr_debug.c,v 1.2 2021/08/14 16:14:56 christos Exp $         */
2 
3 /* thr_debug.c - wrapper around the chosen thread wrapper, for debugging. */
4 /* $OpenLDAP$ */
5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
6  *
7  * Copyright 2005-2021 The OpenLDAP Foundation.
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted only as authorized by the OpenLDAP
12  * Public License.
13  *
14  * A copy of this license is available in file LICENSE in the
15  * top-level directory of the distribution or, alternatively, at
16  * <http://www.OpenLDAP.org/license.html>.
17  */
18 
19 /*
20  * This package provides several types of thread operation debugging:
21  *
22  * - Check the results of operations on threads, mutexes, condition
23  *   variables and read/write locks.  Also check some thread pool
24  *   operations, but not those for which failure can happen in normal
25  *   slapd operation.
26  *
27  * - Wrap those types except threads and pools in structs with state
28  *   information, and check that on all operations:
29  *
30  *   + Check that the resources are initialized and are only used at
31  *     their original address (i.e. not realloced or copied).
32  *
33  *   + Check the owner (thread ID) on mutex operations.
34  *
35  *   + Optionally allocate a reference to a byte of dummy memory.
36  *     This lets malloc debuggers see some incorrect use as memory
37  *     leaks, access to freed memory, etc.
38  *
39  * - Print an error message and by default abort() upon errors.
40  *
41  * - Print a count of leaked thread resources after cleanup.
42  *
43  * Compile-time (./configure) setup:  Macros defined in CPPFLAGS.
44  *
45  *   LDAP_THREAD_DEBUG or LDAP_THREAD_DEBUG=2
46  *      Enables debugging, but value & 2 turns off type wrapping.
47  *
48  *   LDAP_UINTPTR_T=integer type to hold pointers, preferably unsigned.
49  *      Used by dummy memory option "scramble". Default = unsigned long.
50  *
51  *   LDAP_DEBUG_THREAD_NONE = initializer for a "no thread" thread ID.
52  *
53  *   In addition, you may need to set up an implementation-specific way
54  *      to enable whatever error checking your thread library provides.
55  *      Currently only implemented for Posix threads (pthreads), where
56  *      you may need to define LDAP_INT_THREAD_MUTEXATTR.  The default
57  *      is PTHREAD_MUTEX_ERRORCHECK, or PTHREAD_MUTEX_ERRORCHECK_NP for
58  *      Linux threads.  See pthread_mutexattr_settype(3).
59  *
60  * Run-time configuration:
61  *
62  *  Memory debugging tools:
63  *   Tools that report uninitialized memory accesses should disable
64  *   such warnings about the function debug_already_initialized().
65  *   Alternatively, include "noreinit" (below) in $LDAP_THREAD_DEBUG.
66  *
67  *  Environment variable $LDAP_THREAD_DEBUG:
68  *   The variable may contain a comma- or space-separated option list.
69  *   Options:
70  *      off      - Disable this package.  (It still slows things down).
71  *      tracethreads - Report create/join/exit/kill of threads.
72  *      noabort  - Do not abort() on errors.
73  *      noerror  - Do not report errors.  Implies noabort.
74  *      nocount  - Do not report counts of unreleased resources.
75  *      nosync   - Disable tests that use synchronization and thus
76  *                 clearly affect thread scheduling:
77  *                 Implies nocount, and cancels threadID if that is set.
78  *                 Note that if you turn on tracethreads or malloc
79  *                 debugging, these also use library calls which may
80  *                 affect thread scheduling (fprintf and malloc).
81  *   The following options do not apply if type wrapping is disabled:
82  *      nomem    - Do not check memory operations.
83  *                 Implies noreinit,noalloc.
84  *      noreinit - Do not catch reinitialization of existing resources.
85  *                 (That test accesses uninitialized memory).
86  *      threadID - Trace thread IDs.  Currently mostly useless.
87  *     Malloc debugging -- allocate dummy memory for initialized
88  *     resources, so malloc debuggers will report them as memory leaks:
89  *      noalloc  - Default.  Do not allocate dummy memory.
90  *      alloc    - Store a pointer to dummy memory.   However, leak
91  *                 detectors might not catch unreleased resources in
92  *                 global variables.
93  *      scramble - Store bitwise complement of dummy memory pointer.
94  *                 That never escapes memory leak detectors -
95  *                 but detection while the program is running will
96  *                 report active resources as leaks.  Do not
97  *                 use this if a garbage collector is in use:-)
98  *      adjptr   - Point to end of dummy memory.
99  *                 Purify reports these as "potential leaks" (PLK).
100  *                 I have not checked other malloc debuggers.
101  */
102 
103 #include <sys/cdefs.h>
104 __RCSID("$NetBSD: thr_debug.c,v 1.2 2021/08/14 16:14:56 christos Exp $");
105 
106 #include "portable.h"
107 
108 #if defined( LDAP_THREAD_DEBUG )
109 
110 #include <stdio.h>
111 #include <ac/errno.h>
112 #include <ac/stdlib.h>
113 #include <ac/string.h>
114 
115 #include "ldap_pvt_thread.h" /* Get the thread interface */
116 #define LDAP_THREAD_IMPLEMENTATION
117 #define LDAP_THREAD_DEBUG_IMPLEMENTATION
118 #define LDAP_THREAD_RDWR_IMPLEMENTATION
119 #define LDAP_THREAD_POOL_IMPLEMENTATION
120 #include "ldap_thr_debug.h"  /* Get the underlying implementation */
121 
122 #ifndef LDAP_THREAD_DEBUG_WRAP
123 #undef    LDAP_THREAD_DEBUG_THREAD_ID
124 #elif !defined LDAP_THREAD_DEBUG_THREAD_ID
125 #define   LDAP_THREAD_DEBUG_THREAD_ID 1
126 #endif
127 
128 /* Use native malloc - the OpenLDAP wrappers may defeat malloc debuggers */
129 #undef malloc
130 #undef calloc
131 #undef realloc
132 #undef free
133 
134 
135 /* Options from environment variable $LDAP_THREAD_DEBUG */
136 enum { Count_no = 0, Count_yes, Count_reported, Count_reported_more };
137 static int count = Count_yes;
138 #ifdef LDAP_THREAD_DEBUG_WRAP
139 enum { Wrap_noalloc, Wrap_alloc, Wrap_scramble, Wrap_adjptr };
140 static int wraptype = Wrap_noalloc, wrap_offset, unwrap_offset;
141 static int nomem, noreinit;
142 #endif
143 #if LDAP_THREAD_DEBUG_THREAD_ID +0
144 static int threadID;
145 #else
146 enum { threadID = 0 };
147 #endif
148 static int nodebug, noabort, noerror, nosync, tracethreads;
149 static int wrap_threads;
150 static int options_done;
151 
152 
153 /* ldap_pvt_thread_initialize() called, ldap_pvt_thread_destroy() not called */
154 static int threading_enabled;
155 
156 
157 /* Resource counts */
158 enum {
159           Idx_unexited_thread, Idx_unjoined_thread, Idx_locked_mutex,
160           Idx_mutex, Idx_cond, Idx_rdwr, Idx_tpool, Idx_max
161 };
162 static int resource_counts[Idx_max];
163 static const char *const resource_names[] = {
164           "unexited threads", "unjoined threads", "locked mutexes",
165           "mutexes", "conds", "rdwrs", "thread pools"
166 };
167 static ldap_int_thread_mutex_t resource_mutexes[Idx_max];
168 
169 
170 /* Hide pointers from malloc debuggers. */
171 #define SCRAMBLE(ptr) (~(LDAP_UINTPTR_T) (ptr))
172 #define UNSCRAMBLE_usagep(num) ((ldap_debug_usage_info_t *) ~(num))
173 #define UNSCRAMBLE_dummyp(num) ((unsigned char *) ~(num))
174 
175 
176 #define WARN(var, msg)   (warn (__FILE__, __LINE__, (msg), #var, (var)))
177 #define WARN_IF(rc, msg) {if (rc) warn (__FILE__, __LINE__, (msg), #rc, (rc));}
178 
179 #define ERROR(var, msg) { \
180           if (!noerror) { \
181                     errmsg(__FILE__, __LINE__, (msg), #var, (var)); \
182                     if( !noabort ) abort(); \
183           } \
184 }
185 
186 #define ERROR_IF(rc, msg) { \
187           if (!noerror) { \
188                     int rc_ = (rc); \
189                     if (rc_) { \
190                               errmsg(__FILE__, __LINE__, (msg), #rc, rc_); \
191                               if( !noabort ) abort(); \
192                     } \
193           } \
194 }
195 
196 #ifdef LDAP_THREAD_DEBUG_WRAP
197 #define MEMERROR_IF(rc, msg, mem_act) { \
198           if (!noerror) { \
199                     int rc_ = (rc); \
200                     if (rc_) { \
201                               errmsg(__FILE__, __LINE__, (msg), #rc, rc_); \
202                               if( wraptype != Wrap_noalloc ) { mem_act; } \
203                               if( !noabort ) abort(); \
204                     } \
205           } \
206 }
207 #endif /* LDAP_THREAD_DEBUG_WRAP */
208 
209 #if 0
210 static void
211 warn( const char *file, int line, const char *msg, const char *var, int val )
212 {
213           fprintf( stderr,
214                     (strpbrk( var, "!=" )
215                      ? "%s:%d: %s warning: %s\n"
216                      : "%s:%d: %s warning: %s is %d\n"),
217                     file, line, msg, var, val );
218 }
219 #endif
220 
221 static void
errmsg(const char * file,int line,const char * msg,const char * var,int val)222 errmsg( const char *file, int line, const char *msg, const char *var, int val )
223 {
224           fprintf( stderr,
225                     (strpbrk( var, "!=" )
226                      ? "%s:%d: %s error: %s\n"
227                      : "%s:%d: %s error: %s is %d\n"),
228                     file, line, msg, var, val );
229 }
230 
231 static void
count_resource_leaks(void)232 count_resource_leaks( void )
233 {
234           int i, j;
235           char errbuf[200];
236           if( count == Count_yes ) {
237                     count = Count_reported;
238 #if 0 /* Could break if there are still threads after atexit */
239                     for( i = j = 0; i < Idx_max; i++ )
240                               j |= ldap_int_thread_mutex_destroy( &resource_mutexes[i] );
241                     WARN_IF( j, "ldap_debug_thread_destroy:mutexes" );
242 #endif
243                     for( i = j = 0; i < Idx_max; i++ )
244                               if( resource_counts[i] )
245                                         j += sprintf( errbuf + j, ", %d %s",
246                                                   resource_counts[i], resource_names[i] );
247                     if( j )
248                               fprintf( stderr, "== thr_debug: Leaked%s. ==\n", errbuf + 1 );
249           }
250 }
251 
252 static void
get_options(void)253 get_options( void )
254 {
255           static const struct option_info_s {
256                     const char          *name;
257                     int                 *var, val;
258           } option_info[] = {
259                     { "off",        &nodebug,  1 },
260                     { "noabort",    &noabort,  1 },
261                     { "noerror",    &noerror,  1 },
262                     { "nocount",    &count,    Count_no },
263                     { "nosync",     &nosync,   1 },
264 #if LDAP_THREAD_DEBUG_THREAD_ID +0
265                     { "threadID",   &threadID, 1 },
266 #endif
267 #ifdef LDAP_THREAD_DEBUG_WRAP
268                     { "nomem",      &nomem,    1 },
269                     { "noreinit",   &noreinit, 1 },
270                     { "noalloc",    &wraptype, Wrap_noalloc },
271                     { "alloc",      &wraptype, Wrap_alloc },
272                     { "adjptr",     &wraptype, Wrap_adjptr },
273                     { "scramble",       &wraptype, Wrap_scramble },
274 #endif
275                     { "tracethreads", &tracethreads, 1 },
276                     { NULL, NULL, 0 }
277           };
278           const char *s = getenv( "LDAP_THREAD_DEBUG" );
279           if( s != NULL ) {
280                     while( *(s += strspn( s, ", \t\r\n" )) != '\0' ) {
281                               size_t optlen = strcspn( s, ", \t\r\n" );
282                               const struct option_info_s *oi = option_info;
283                               while( oi->name &&
284                                            (strncasecmp( oi->name, s, optlen ) || oi->name[optlen]) )
285                                         oi++;
286                               if( oi->name )
287                                         *oi->var = oi->val;
288                               else
289                                         fprintf( stderr,
290                                                   "== thr_debug: Unknown $%s option '%.*s' ==\n",
291                                                   "LDAP_THREAD_DEBUG", (int) optlen, s );
292                               s += optlen;
293                     }
294           }
295           if( nodebug ) {
296                     tracethreads = 0;
297                     nosync = noerror = 1;
298           }
299           if( nosync )
300                     count = Count_no;
301           if( noerror )
302                     noabort = 1;
303 #if LDAP_THREAD_DEBUG_THREAD_ID +0
304           if( nosync )
305                     threadID = 0;
306 #endif
307 #ifdef LDAP_THREAD_DEBUG_WRAP
308           if( noerror )
309                     nomem = 1;
310           if( !nomem ) {
311                     static const ldap_debug_usage_info_t usage;
312                     if( sizeof(LDAP_UINTPTR_T) < sizeof(unsigned char *)
313                               || sizeof(LDAP_UINTPTR_T) < sizeof(ldap_debug_usage_info_t *)
314                               || UNSCRAMBLE_usagep( SCRAMBLE( &usage ) ) != &usage
315                               || UNSCRAMBLE_dummyp( SCRAMBLE( (unsigned char *) 0 ) ) )
316                     {
317                               fputs( "== thr_debug: Memory checks unsupported, "
318                                         "adding nomem to $LDAP_THREAD_DEBUG ==\n", stderr );
319                               nomem = 1;
320                     }
321           }
322           if( nomem ) {
323                     noreinit = 1;
324                     wraptype = Wrap_noalloc;
325           }
326           unwrap_offset = -(wrap_offset = (wraptype == Wrap_adjptr));
327 #endif
328           wrap_threads = (tracethreads || threadID || count);
329           options_done = 1;
330 }
331 
332 
333 #ifndef LDAP_THREAD_DEBUG_WRAP
334 
335 #define   WRAPPED(ptr)                            (ptr)
336 #define   GET_OWNER(ptr)                          0
337 #define   SET_OWNER(ptr, thread)        ((void) 0)
338 #define   RESET_OWNER(ptr)              ((void) 0)
339 #define   ASSERT_OWNER(ptr, msg)        ((void) 0)
340 #define   ASSERT_NO_OWNER(ptr, msg) ((void) 0)
341 
342 #define init_usage(ptr, msg)  ((void) 0)
343 #define check_usage(ptr, msg) ((void) 0)
344 #define destroy_usage(ptr)              ((void) 0)
345 
346 #else /* LDAP_THREAD_DEBUG_WRAP */
347 
348 /* Specialize this if the initializer is not appropriate. */
349 /* The ASSERT_NO_OWNER() definition may also need an override. */
350 #ifndef LDAP_DEBUG_THREAD_NONE
351 #define   LDAP_DEBUG_THREAD_NONE { -1 } /* "no thread" ldap_int_thread_t value */
352 #endif
353 
354 static const ldap_int_thread_t ldap_debug_thread_none = LDAP_DEBUG_THREAD_NONE;
355 
356 #define THREAD_MUTEX_OWNER(mutex) \
357           ldap_int_thread_equal( (mutex)->owner, ldap_int_thread_self() )
358 
359 void
ldap_debug_thread_assert_mutex_owner(const char * file,int line,const char * msg,ldap_pvt_thread_mutex_t * mutex)360 ldap_debug_thread_assert_mutex_owner(
361           const char *file,
362           int line,
363           const char *msg,
364           ldap_pvt_thread_mutex_t *mutex )
365 {
366           if( !(noerror || THREAD_MUTEX_OWNER( mutex )) ) {
367                     errmsg( file, line, msg, "ASSERT_MUTEX_OWNER", 0 );
368                     if( !noabort ) abort();
369           }
370 }
371 
372 #define   WRAPPED(ptr)                            (&(ptr)->wrapped)
373 #define   GET_OWNER(ptr)                          ((ptr)->owner)
374 #define   SET_OWNER(ptr, thread)        ((ptr)->owner = (thread))
375 #define   RESET_OWNER(ptr)              ((ptr)->owner = ldap_debug_thread_none)
376 #define   ASSERT_OWNER(ptr, msg)        ERROR_IF( !THREAD_MUTEX_OWNER( ptr ), msg )
377 #ifndef   ASSERT_NO_OWNER
378 #define   ASSERT_NO_OWNER(ptr, msg) ERROR_IF( \
379           !ldap_int_thread_equal( (ptr)->owner, ldap_debug_thread_none ), msg )
380 #endif
381 
382 /* Try to provoke memory access error (for malloc debuggers) */
383 #define PEEK(mem) {if (-*(volatile const unsigned char *)(mem)) debug_noop();}
384 
385 static void debug_noop( void );
386 static int debug_already_initialized( const ldap_debug_usage_info_t *usage );
387 
388 /* Name used for clearer error message */
389 #define IS_COPY_OR_MOVED(usage) ((usage)->self != SCRAMBLE( usage ))
390 
391 #define DUMMY_ADDR(usage) \
392           (wraptype == Wrap_scramble \
393            ? UNSCRAMBLE_dummyp( (usage)->mem.num ) \
394            : (usage)->mem.ptr + unwrap_offset)
395 
396 /* Mark resource as initialized */
397 static void
init_usage(ldap_debug_usage_info_t * usage,const char * msg)398 init_usage( ldap_debug_usage_info_t *usage, const char *msg )
399 {
400           if( !options_done )
401                     get_options();
402           if( !nomem ) {
403                     if( !noreinit ) {
404                               MEMERROR_IF( debug_already_initialized( usage ), msg, {
405                                         /* Provoke malloc debuggers */
406                                         unsigned char *dummy = DUMMY_ADDR( usage );
407                                         PEEK( dummy );
408                                         free( dummy );
409                                         free( dummy );
410                               } );
411                     }
412                     if( wraptype != Wrap_noalloc ) {
413                               unsigned char *dummy = malloc( 1 );
414                               assert( dummy != NULL );
415                               if( wraptype == Wrap_scramble ) {
416                                         usage->mem.num = SCRAMBLE( dummy );
417                                         /* Verify that ptr<->integer casts work on this host */
418                                         assert( UNSCRAMBLE_dummyp( usage->mem.num ) == dummy );
419                               } else {
420                                         usage->mem.ptr = dummy + wrap_offset;
421                               }
422                     }
423           } else {
424                     /* Unused, but set for readability in debugger */
425                     usage->mem.ptr = NULL;
426           }
427           usage->self = SCRAMBLE( usage );        /* If nomem, only for debugger */
428           usage->magic = ldap_debug_magic;
429           usage->state = ldap_debug_state_inited;
430 }
431 
432 /* Check that resource is initialized and not copied/realloced */
433 static void
check_usage(const ldap_debug_usage_info_t * usage,const char * msg)434 check_usage( const ldap_debug_usage_info_t *usage, const char *msg )
435 {
436           enum { Is_destroyed = 1 };    /* Name used for clearer error message */
437 
438           if( usage->magic != ldap_debug_magic ) {
439                     ERROR( usage->magic, msg );
440                     return;
441           }
442           switch( usage->state ) {
443           case ldap_debug_state_destroyed:
444                     MEMERROR_IF( Is_destroyed, msg, {
445                               PEEK( DUMMY_ADDR( usage ) );
446                     } );
447                     break;
448           default:
449                     ERROR( usage->state, msg );
450                     break;
451           case ldap_debug_state_inited:
452                     if( !nomem ) {
453                               MEMERROR_IF( IS_COPY_OR_MOVED( usage ), msg, {
454                                         PEEK( DUMMY_ADDR( usage ) );
455                                         PEEK( UNSCRAMBLE_usagep( usage->self ) );
456                               } );
457                     }
458                     break;
459           }
460 }
461 
462 /* Mark resource as destroyed. */
463 /* Does not check for errors, call check_usage()/init_usage() first. */
464 static void
destroy_usage(ldap_debug_usage_info_t * usage)465 destroy_usage( ldap_debug_usage_info_t *usage )
466 {
467           if( usage->state == ldap_debug_state_inited ) {
468                     if( wraptype != Wrap_noalloc ) {
469                               free( DUMMY_ADDR( usage ) );
470                               /* Do not reset the DUMMY_ADDR, leave it for malloc debuggers
471                                * in case the resource is used after it is freed. */
472                     }
473                     usage->state = ldap_debug_state_destroyed;
474           }
475 }
476 
477 /* Define these after they are used, so they are hopefully not inlined */
478 
479 static void
debug_noop(void)480 debug_noop( void )
481 {
482 }
483 
484 /*
485  * Valid programs access uninitialized memory here unless "noreinit".
486  *
487  * Returns true if the resource is initialized and not copied/realloced.
488  */
489 LDAP_GCCATTR((noinline))
490 static int
debug_already_initialized(const ldap_debug_usage_info_t * usage)491 debug_already_initialized( const ldap_debug_usage_info_t *usage )
492 {
493           /*
494            * 'ret' keeps the Valgrind warning "Conditional jump or move
495            * depends on uninitialised value(s)" _inside_ this function.
496            */
497           volatile int ret = 0;
498           if( usage->state == ldap_debug_state_inited )
499                     if( !IS_COPY_OR_MOVED( usage ) )
500                   if( usage->magic == ldap_debug_magic )
501                                         ret = 1;
502           return ret;
503 }
504 
505 #endif /* LDAP_THREAD_DEBUG_WRAP */
506 
507 
508 #if !(LDAP_THREAD_DEBUG_THREAD_ID +0)
509 
510 typedef void ldap_debug_thread_t;
511 #define init_thread_info()    {}
512 #define with_thread_info_lock(statements) { statements; }
513 #define thread_info_detached(t)         0
514 #define add_thread_info(msg, thr, det)  ((void) 0)
515 #define remove_thread_info(tinfo, msg)  ((void) 0)
516 #define get_thread_info(thread, msg)    NULL
517 
518 #else /* LDAP_THREAD_DEBUG_THREAD_ID */
519 
520 /*
521  * Thread ID tracking.  Currently achieves little.
522  * Should be either expanded or deleted.
523  */
524 
525 /*
526  * Array of threads.  Used instead of making ldap_pvt_thread_t a wrapper
527  * around ldap_int_thread_t, which would slow down ldap_pvt_thread_self().
528  */
529 typedef struct {
530           ldap_pvt_thread_t           wrapped;
531           ldap_debug_usage_info_t     usage;
532           int                         detached;
533           int                         idx;
534 } ldap_debug_thread_t;
535 
536 static ldap_debug_thread_t      **thread_info;
537 static unsigned int             thread_info_size, thread_info_used;
538 static ldap_int_thread_mutex_t  thread_info_mutex;
539 
540 #define init_thread_info() { \
541           if( threadID ) { \
542                     int mutex_init_rc = ldap_int_thread_mutex_init( &thread_info_mutex ); \
543                     assert( mutex_init_rc == 0 ); \
544           } \
545 }
546 
547 #define with_thread_info_lock(statements) { \
548           int rc_wtl_ = ldap_int_thread_mutex_lock( &thread_info_mutex ); \
549           assert( rc_wtl_ == 0 ); \
550           { statements; } \
551           rc_wtl_ = ldap_int_thread_mutex_unlock( &thread_info_mutex ); \
552           assert( rc_wtl_ == 0 ); \
553 }
554 
555 #define thread_info_detached(t) ((t)->detached)
556 
557 static void
add_thread_info(const char * msg,const ldap_pvt_thread_t * thread,int detached)558 add_thread_info(
559           const char *msg,
560           const ldap_pvt_thread_t *thread,
561           int detached )
562 {
563           ldap_debug_thread_t *t;
564 
565           if( thread_info_used >= thread_info_size ) {
566                     unsigned int more = thread_info_size + 8;
567                     unsigned int new_size = thread_info_size + more;
568 
569                     t = calloc( more, sizeof(ldap_debug_thread_t) );
570                     assert( t != NULL );
571                     thread_info = realloc( thread_info, new_size * sizeof(*thread_info) );
572                     assert( thread_info != NULL );
573                     do {
574                               t->idx = thread_info_size;
575                               thread_info[thread_info_size++] = t++;
576                     } while( thread_info_size < new_size );
577           }
578 
579           t = thread_info[thread_info_used];
580           init_usage( &t->usage, msg );
581           t->wrapped = *thread;
582           t->detached = detached;
583           thread_info_used++;
584 }
585 
586 static void
remove_thread_info(ldap_debug_thread_t * t,const char * msg)587 remove_thread_info( ldap_debug_thread_t *t, const char *msg )
588 {
589                     ldap_debug_thread_t *last;
590                     int idx;
591                     check_usage( &t->usage, msg );
592                     destroy_usage( &t->usage );
593                     idx = t->idx;
594                     assert( thread_info[idx] == t );
595                     last = thread_info[--thread_info_used];
596                     assert( last->idx == thread_info_used );
597                     (thread_info[idx]              = last)->idx = idx;
598                     (thread_info[thread_info_used] = t   )->idx = thread_info_used;
599 }
600 
601 static ldap_debug_thread_t *
get_thread_info(ldap_pvt_thread_t thread,const char * msg)602 get_thread_info( ldap_pvt_thread_t thread, const char *msg )
603 {
604           unsigned int i;
605           ldap_debug_thread_t *t;
606           for( i = 0; i < thread_info_used; i++ ) {
607                     if( ldap_pvt_thread_equal( thread, thread_info[i]->wrapped ) )
608                               break;
609           }
610           ERROR_IF( i == thread_info_used, msg );
611           t = thread_info[i];
612           check_usage( &t->usage, msg );
613           return t;
614 }
615 
616 #endif /* LDAP_THREAD_DEBUG_THREAD_ID */
617 
618 
619 static char *
thread_name(char * buf,int bufsize,ldap_pvt_thread_t thread)620 thread_name( char *buf, int bufsize, ldap_pvt_thread_t thread )
621 {
622           int i;
623           --bufsize;
624           if( bufsize > 2*sizeof(thread) )
625                     bufsize = 2*sizeof(thread);
626           for( i = 0; i < bufsize; i += 2 )
627                     snprintf( buf+i, 3, "%02x", ((unsigned char *)&thread)[i/2] );
628           return buf;
629 }
630 
631 
632 /* Add <adjust> (+/-1) to resource count <which> unless "nocount". */
633 static void
adjust_count(int which,int adjust)634 adjust_count( int which, int adjust )
635 {
636           int rc;
637           switch( count ) {
638           case Count_no:
639                     break;
640           case Count_yes:
641                     rc = ldap_int_thread_mutex_lock( &resource_mutexes[which] );
642                     assert( rc == 0 );
643                     resource_counts[which] += adjust;
644                     rc = ldap_int_thread_mutex_unlock( &resource_mutexes[which] );
645                     assert( rc == 0 );
646                     break;
647           case Count_reported:
648                     fputs( "== thr_debug: More thread activity after exit ==\n", stderr );
649                     count = Count_reported_more;
650                     /* FALL THROUGH */
651           case Count_reported_more:
652                     /* Not used, but result might be inspected with debugger */
653                     /* (Hopefully threading is disabled by now...) */
654                     resource_counts[which] += adjust;
655                     break;
656           }
657 }
658 
659 
660 /* Wrappers for LDAP_THREAD_IMPLEMENTATION: */
661 
662 /* Used instead of ldap_int_thread_initialize by ldap_pvt_thread_initialize */
663 int
ldap_debug_thread_initialize(void)664 ldap_debug_thread_initialize( void )
665 {
666           int i, rc, rc2;
667           if( !options_done )
668                     get_options();
669           ERROR_IF( threading_enabled, "ldap_debug_thread_initialize" );
670           threading_enabled = 1;
671           rc = ldap_int_thread_initialize();
672           if( rc ) {
673                     ERROR( rc, "ldap_debug_thread_initialize:threads" );
674                     threading_enabled = 0;
675           } else {
676                     init_thread_info();
677                     if( count != Count_no ) {
678                               for( i = rc2 = 0; i < Idx_max; i++ )
679                                         rc2 |= ldap_int_thread_mutex_init( &resource_mutexes[i] );
680                               assert( rc2 == 0 );
681                               /* FIXME: Only for static libldap as in init.c? If so, why? */
682                               atexit( count_resource_leaks );
683                     }
684           }
685           return rc;
686 }
687 
688 /* Used instead of ldap_int_thread_destroy by ldap_pvt_thread_destroy */
689 int
ldap_debug_thread_destroy(void)690 ldap_debug_thread_destroy( void )
691 {
692           int rc;
693           ERROR_IF( !threading_enabled, "ldap_debug_thread_destroy" );
694           /* sleep(1) -- need to wait for thread pool to finish? */
695           rc = ldap_int_thread_destroy();
696           if( rc ) {
697                     ERROR( rc, "ldap_debug_thread_destroy:threads" );
698           } else {
699                     threading_enabled = 0;
700           }
701           return rc;
702 }
703 
704 int
ldap_pvt_thread_set_concurrency(int n)705 ldap_pvt_thread_set_concurrency( int n )
706 {
707           int rc;
708           ERROR_IF( !threading_enabled, "ldap_pvt_thread_set_concurrency" );
709           rc = ldap_int_thread_set_concurrency( n );
710           ERROR_IF( rc, "ldap_pvt_thread_set_concurrency" );
711           return rc;
712 }
713 
714 int
ldap_pvt_thread_get_concurrency(void)715 ldap_pvt_thread_get_concurrency( void )
716 {
717           int rc;
718           ERROR_IF( !threading_enabled, "ldap_pvt_thread_get_concurrency" );
719           rc = ldap_int_thread_get_concurrency();
720           ERROR_IF( rc, "ldap_pvt_thread_get_concurrency" );
721           return rc;
722 }
723 
724 unsigned int
ldap_pvt_thread_sleep(unsigned int interval)725 ldap_pvt_thread_sleep( unsigned int interval )
726 {
727           int rc;
728           ERROR_IF( !threading_enabled, "ldap_pvt_thread_sleep" );
729           rc = ldap_int_thread_sleep( interval );
730           ERROR_IF( rc, "ldap_pvt_thread_sleep" );
731           return 0;
732 }
733 
734 static void
thread_exiting(const char * how,const char * msg)735 thread_exiting( const char *how, const char *msg )
736 {
737           ldap_pvt_thread_t thread;
738 #if 0 /* Detached threads may exit after ldap_debug_thread_destroy(). */
739           ERROR_IF( !threading_enabled, msg );
740 #endif
741           thread = ldap_pvt_thread_self();
742           if( tracethreads ) {
743                     char buf[40];
744                     fprintf( stderr, "== thr_debug: %s thread %s ==\n",
745                               how, thread_name( buf, sizeof(buf), thread ) );
746           }
747           if( threadID ) {
748                     with_thread_info_lock({
749                               ldap_debug_thread_t *t = get_thread_info( thread, msg );
750                               if( thread_info_detached( t ) )
751                                         remove_thread_info( t, msg );
752                     });
753           }
754           adjust_count( Idx_unexited_thread, -1 );
755 }
756 
757 void
ldap_pvt_thread_exit(void * retval)758 ldap_pvt_thread_exit( void *retval )
759 {
760           thread_exiting( "Exiting", "ldap_pvt_thread_exit" );
761           ldap_int_thread_exit( retval );
762 }
763 
764 typedef struct {
765           void *(*start_routine)( void * );
766           void *arg;
767 } ldap_debug_thread_call_t;
768 
769 static void *
ldap_debug_thread_wrapper(void * arg)770 ldap_debug_thread_wrapper( void *arg )
771 {
772           void *ret;
773           ldap_debug_thread_call_t call = *(ldap_debug_thread_call_t *)arg;
774           free( arg );
775           ret = call.start_routine( call.arg );
776           thread_exiting( "Returning from", "ldap_debug_thread_wrapper" );
777           return ret;
778 }
779 
780 int
ldap_pvt_thread_create(ldap_pvt_thread_t * thread,int detach,void * (* start_routine)(void *),void * arg)781 ldap_pvt_thread_create(
782           ldap_pvt_thread_t *thread,
783           int detach,
784           void *(*start_routine)( void * ),
785           void *arg )
786 {
787           int rc;
788           if( !options_done )
789                     get_options();
790           ERROR_IF( !threading_enabled, "ldap_pvt_thread_create" );
791 
792           if( wrap_threads ) {
793                     ldap_debug_thread_call_t *call = malloc(
794                               sizeof( ldap_debug_thread_call_t ) );
795                     assert( call != NULL );
796                     call->start_routine = start_routine;
797                     call->arg = arg;
798                     start_routine = ldap_debug_thread_wrapper;
799                     arg = call;
800           }
801           if( threadID ) {
802                     with_thread_info_lock({
803                               rc = ldap_int_thread_create( thread, detach, start_routine, arg );
804                               if( rc == 0 )
805                                         add_thread_info( "ldap_pvt_thread_create", thread, detach );
806                     });
807           } else {
808                     rc = ldap_int_thread_create( thread, detach, start_routine, arg );
809           }
810           if( rc ) {
811                     ERROR( rc, "ldap_pvt_thread_create" );
812                     if( wrap_threads )
813                               free( arg );
814           } else {
815                     if( tracethreads ) {
816                               char buf[40], buf2[40];
817                               fprintf( stderr,
818                                         "== thr_debug: Created thread %s%s from thread %s ==\n",
819                                         thread_name( buf, sizeof(buf), *thread ),
820                                         detach ? " (detached)" : "",
821                                         thread_name( buf2, sizeof(buf2), ldap_pvt_thread_self() ) );
822                     }
823                     adjust_count( Idx_unexited_thread, +1 );
824                     if( !detach )
825                               adjust_count( Idx_unjoined_thread, +1 );
826           }
827           return rc;
828 }
829 
830 int
ldap_pvt_thread_join(ldap_pvt_thread_t thread,void ** thread_return)831 ldap_pvt_thread_join( ldap_pvt_thread_t thread, void **thread_return )
832 {
833           int rc;
834           ldap_debug_thread_t *t = NULL;
835           ERROR_IF( !threading_enabled, "ldap_pvt_thread_join" );
836           if( tracethreads ) {
837                     char buf[40], buf2[40];
838                     fprintf( stderr, "== thr_debug: Joining thread %s in thread %s ==\n",
839                               thread_name( buf, sizeof(buf), thread ),
840                               thread_name( buf2, sizeof(buf2), ldap_pvt_thread_self() ) );
841           }
842           if( threadID )
843                     with_thread_info_lock( {
844                               t = get_thread_info( thread, "ldap_pvt_thread_join" );
845                               ERROR_IF( thread_info_detached( t ), "ldap_pvt_thread_join" );
846                     } );
847           rc = ldap_int_thread_join( thread, thread_return );
848           if( rc ) {
849                     ERROR( rc, "ldap_pvt_thread_join" );
850           } else {
851                     if( threadID )
852                               with_thread_info_lock(
853                                         remove_thread_info( t, "ldap_pvt_thread_join" ) );
854                     adjust_count( Idx_unjoined_thread, -1 );
855           }
856 
857           return rc;
858 }
859 
860 int
ldap_pvt_thread_kill(ldap_pvt_thread_t thread,int signo)861 ldap_pvt_thread_kill( ldap_pvt_thread_t thread, int signo )
862 {
863           int rc;
864           ERROR_IF( !threading_enabled, "ldap_pvt_thread_kill" );
865           if( tracethreads ) {
866                     char buf[40], buf2[40];
867                     fprintf( stderr,
868                               "== thr_debug: Killing thread %s (sig %i) from thread %s ==\n",
869                               thread_name( buf, sizeof(buf), thread ), signo,
870                               thread_name( buf2, sizeof(buf2), ldap_pvt_thread_self() ) );
871           }
872           rc = ldap_int_thread_kill( thread, signo );
873           ERROR_IF( rc, "ldap_pvt_thread_kill" );
874           return rc;
875 }
876 
877 int
ldap_pvt_thread_yield(void)878 ldap_pvt_thread_yield( void )
879 {
880           int rc;
881           ERROR_IF( !threading_enabled, "ldap_pvt_thread_yield" );
882           rc = ldap_int_thread_yield();
883           ERROR_IF( rc, "ldap_pvt_thread_yield" );
884           return rc;
885 }
886 
887 ldap_pvt_thread_t
ldap_pvt_thread_self(void)888 ldap_pvt_thread_self( void )
889 {
890 #if 0 /* Function is used by ch_free() via slap_sl_contxt() in slapd */
891           ERROR_IF( !threading_enabled, "ldap_pvt_thread_self" );
892 #endif
893           return ldap_int_thread_self();
894 }
895 
896 int
ldap_pvt_thread_cond_init(ldap_pvt_thread_cond_t * cond)897 ldap_pvt_thread_cond_init( ldap_pvt_thread_cond_t *cond )
898 {
899           int rc;
900           init_usage( &cond->usage, "ldap_pvt_thread_cond_init" );
901           rc = ldap_int_thread_cond_init( WRAPPED( cond ) );
902           if( rc ) {
903                     ERROR( rc, "ldap_pvt_thread_cond_init" );
904                     destroy_usage( &cond->usage );
905           } else {
906                     adjust_count( Idx_cond, +1 );
907           }
908           return rc;
909 }
910 
911 int
ldap_pvt_thread_cond_destroy(ldap_pvt_thread_cond_t * cond)912 ldap_pvt_thread_cond_destroy( ldap_pvt_thread_cond_t *cond )
913 {
914           int rc;
915           check_usage( &cond->usage, "ldap_pvt_thread_cond_destroy" );
916           rc = ldap_int_thread_cond_destroy( WRAPPED( cond ) );
917           if( rc ) {
918                     ERROR( rc, "ldap_pvt_thread_cond_destroy" );
919           } else {
920                     destroy_usage( &cond->usage );
921                     adjust_count( Idx_cond, -1 );
922           }
923           return rc;
924 }
925 
926 int
ldap_pvt_thread_cond_signal(ldap_pvt_thread_cond_t * cond)927 ldap_pvt_thread_cond_signal( ldap_pvt_thread_cond_t *cond )
928 {
929           int rc;
930           check_usage( &cond->usage, "ldap_pvt_thread_cond_signal" );
931           rc = ldap_int_thread_cond_signal( WRAPPED( cond ) );
932           ERROR_IF( rc, "ldap_pvt_thread_cond_signal" );
933           return rc;
934 }
935 
936 int
ldap_pvt_thread_cond_broadcast(ldap_pvt_thread_cond_t * cond)937 ldap_pvt_thread_cond_broadcast( ldap_pvt_thread_cond_t *cond )
938 {
939           int rc;
940           check_usage( &cond->usage, "ldap_pvt_thread_cond_broadcast" );
941           rc = ldap_int_thread_cond_broadcast( WRAPPED( cond ) );
942           ERROR_IF( rc, "ldap_pvt_thread_cond_broadcast" );
943           return rc;
944 }
945 
946 int
ldap_pvt_thread_cond_wait(ldap_pvt_thread_cond_t * cond,ldap_pvt_thread_mutex_t * mutex)947 ldap_pvt_thread_cond_wait(
948           ldap_pvt_thread_cond_t *cond,
949           ldap_pvt_thread_mutex_t *mutex )
950 {
951           int rc;
952           ldap_int_thread_t owner;
953           check_usage( &cond->usage, "ldap_pvt_thread_cond_wait:cond" );
954           check_usage( &mutex->usage, "ldap_pvt_thread_cond_wait:mutex" );
955           adjust_count( Idx_locked_mutex, -1 );
956           owner = GET_OWNER( mutex );
957           ASSERT_OWNER( mutex, "ldap_pvt_thread_cond_wait" );
958           RESET_OWNER( mutex );
959           rc = ldap_int_thread_cond_wait( WRAPPED( cond ), WRAPPED( mutex ) );
960           ASSERT_NO_OWNER( mutex, "ldap_pvt_thread_cond_wait" );
961           SET_OWNER( mutex, rc ? owner : ldap_int_thread_self() );
962           adjust_count( Idx_locked_mutex, +1 );
963           ERROR_IF( rc, "ldap_pvt_thread_cond_wait" );
964           return rc;
965 }
966 
967 int
ldap_pvt_thread_mutex_recursive_init(ldap_pvt_thread_mutex_t * mutex)968 ldap_pvt_thread_mutex_recursive_init( ldap_pvt_thread_mutex_t *mutex )
969 {
970           int rc;
971           init_usage( &mutex->usage, "ldap_pvt_thread_mutex_recursive_init" );
972           rc = ldap_int_thread_mutex_recursive_init( WRAPPED( mutex ) );
973           if( rc ) {
974                     ERROR( rc, "ldap_pvt_thread_mutex_recursive_init" );
975                     destroy_usage( &mutex->usage );
976           } else {
977                     RESET_OWNER( mutex );
978                     adjust_count( Idx_mutex, +1 );
979           }
980           return rc;
981 }
982 
983 int
ldap_pvt_thread_mutex_init(ldap_pvt_thread_mutex_t * mutex)984 ldap_pvt_thread_mutex_init( ldap_pvt_thread_mutex_t *mutex )
985 {
986           int rc;
987           init_usage( &mutex->usage, "ldap_pvt_thread_mutex_init" );
988           rc = ldap_int_thread_mutex_init( WRAPPED( mutex ) );
989           if( rc ) {
990                     ERROR( rc, "ldap_pvt_thread_mutex_init" );
991                     destroy_usage( &mutex->usage );
992           } else {
993                     RESET_OWNER( mutex );
994                     adjust_count( Idx_mutex, +1 );
995           }
996           return rc;
997 }
998 
999 int
ldap_pvt_thread_mutex_destroy(ldap_pvt_thread_mutex_t * mutex)1000 ldap_pvt_thread_mutex_destroy( ldap_pvt_thread_mutex_t *mutex )
1001 {
1002           int rc;
1003           check_usage( &mutex->usage, "ldap_pvt_thread_mutex_destroy" );
1004           ASSERT_NO_OWNER( mutex, "ldap_pvt_thread_mutex_destroy" );
1005           rc = ldap_int_thread_mutex_destroy( WRAPPED( mutex ) );
1006           if( rc ) {
1007                     ERROR( rc, "ldap_pvt_thread_mutex_destroy" );
1008           } else {
1009                     destroy_usage( &mutex->usage );
1010                     RESET_OWNER( mutex );
1011                     adjust_count( Idx_mutex, -1 );
1012           }
1013           return rc;
1014 }
1015 
1016 int
ldap_pvt_thread_mutex_lock(ldap_pvt_thread_mutex_t * mutex)1017 ldap_pvt_thread_mutex_lock( ldap_pvt_thread_mutex_t *mutex )
1018 {
1019           int rc;
1020           check_usage( &mutex->usage, "ldap_pvt_thread_mutex_lock" );
1021           rc = ldap_int_thread_mutex_lock( WRAPPED( mutex ) );
1022           if( rc ) {
1023                     ERROR_IF( rc, "ldap_pvt_thread_mutex_lock" );
1024           } else {
1025                     ASSERT_NO_OWNER( mutex, "ldap_pvt_thread_mutex_lock" );
1026                     SET_OWNER( mutex, ldap_int_thread_self() );
1027                     adjust_count( Idx_locked_mutex, +1 );
1028           }
1029           return rc;
1030 }
1031 
1032 int
ldap_pvt_thread_mutex_trylock(ldap_pvt_thread_mutex_t * mutex)1033 ldap_pvt_thread_mutex_trylock( ldap_pvt_thread_mutex_t *mutex )
1034 {
1035           int rc;
1036           check_usage( &mutex->usage, "ldap_pvt_thread_mutex_trylock" );
1037           rc = ldap_int_thread_mutex_trylock( WRAPPED( mutex ) );
1038           if( rc == 0 ) {
1039                     ASSERT_NO_OWNER( mutex, "ldap_pvt_thread_mutex_trylock" );
1040                     SET_OWNER( mutex, ldap_int_thread_self() );
1041                     adjust_count( Idx_locked_mutex, +1 );
1042           }
1043           return rc;
1044 }
1045 
1046 int
ldap_pvt_thread_mutex_unlock(ldap_pvt_thread_mutex_t * mutex)1047 ldap_pvt_thread_mutex_unlock( ldap_pvt_thread_mutex_t *mutex )
1048 {
1049           int rc;
1050           check_usage( &mutex->usage, "ldap_pvt_thread_mutex_unlock" );
1051           ASSERT_OWNER( mutex, "ldap_pvt_thread_mutex_unlock" );
1052           RESET_OWNER( mutex ); /* Breaks if this thread did not own the mutex */
1053           rc = ldap_int_thread_mutex_unlock( WRAPPED( mutex ) );
1054           if( rc ) {
1055                     ERROR_IF( rc, "ldap_pvt_thread_mutex_unlock" );
1056           } else {
1057                     adjust_count( Idx_locked_mutex, -1 );
1058           }
1059           return rc;
1060 }
1061 
1062 
1063 /* Wrappers for LDAP_THREAD_RDWR_IMPLEMENTATION: */
1064 
1065 int
ldap_pvt_thread_rdwr_init(ldap_pvt_thread_rdwr_t * rwlock)1066 ldap_pvt_thread_rdwr_init( ldap_pvt_thread_rdwr_t *rwlock )
1067 {
1068           int rc;
1069           init_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_init" );
1070           rc = ldap_int_thread_rdwr_init( WRAPPED( rwlock ) );
1071           if( rc ) {
1072                     ERROR( rc, "ldap_pvt_thread_rdwr_init" );
1073                     destroy_usage( &rwlock->usage );
1074           } else {
1075                     adjust_count( Idx_rdwr, +1 );
1076           }
1077           return rc;
1078 }
1079 
1080 int
ldap_pvt_thread_rdwr_destroy(ldap_pvt_thread_rdwr_t * rwlock)1081 ldap_pvt_thread_rdwr_destroy( ldap_pvt_thread_rdwr_t *rwlock )
1082 {
1083           int rc;
1084           check_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_destroy" );
1085           rc = ldap_int_thread_rdwr_destroy( WRAPPED( rwlock ) );
1086           if( rc ) {
1087                     ERROR( rc, "ldap_pvt_thread_rdwr_destroy" );
1088           } else {
1089                     destroy_usage( &rwlock->usage );
1090                     adjust_count( Idx_rdwr, -1 );
1091           }
1092           return rc;
1093 }
1094 
1095 int
ldap_pvt_thread_rdwr_rlock(ldap_pvt_thread_rdwr_t * rwlock)1096 ldap_pvt_thread_rdwr_rlock( ldap_pvt_thread_rdwr_t *rwlock )
1097 {
1098           int rc;
1099           check_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_rlock" );
1100           rc = ldap_int_thread_rdwr_rlock( WRAPPED( rwlock ) );
1101           ERROR_IF( rc, "ldap_pvt_thread_rdwr_rlock" );
1102           return rc;
1103 }
1104 
1105 int
ldap_pvt_thread_rdwr_rtrylock(ldap_pvt_thread_rdwr_t * rwlock)1106 ldap_pvt_thread_rdwr_rtrylock( ldap_pvt_thread_rdwr_t *rwlock )
1107 {
1108           check_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_rtrylock" );
1109           return ldap_int_thread_rdwr_rtrylock( WRAPPED( rwlock ) );
1110 }
1111 
1112 int
ldap_pvt_thread_rdwr_runlock(ldap_pvt_thread_rdwr_t * rwlock)1113 ldap_pvt_thread_rdwr_runlock( ldap_pvt_thread_rdwr_t *rwlock )
1114 {
1115           int rc;
1116           check_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_runlock" );
1117           rc = ldap_int_thread_rdwr_runlock( WRAPPED( rwlock ) );
1118           ERROR_IF( rc, "ldap_pvt_thread_rdwr_runlock" );
1119           return rc;
1120 }
1121 
1122 int
ldap_pvt_thread_rdwr_wlock(ldap_pvt_thread_rdwr_t * rwlock)1123 ldap_pvt_thread_rdwr_wlock( ldap_pvt_thread_rdwr_t *rwlock )
1124 {
1125           int rc;
1126           check_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_wlock" );
1127           rc = ldap_int_thread_rdwr_wlock( WRAPPED( rwlock ) );
1128           ERROR_IF( rc, "ldap_pvt_thread_rdwr_wlock" );
1129           return rc;
1130 }
1131 
1132 int
ldap_pvt_thread_rdwr_wtrylock(ldap_pvt_thread_rdwr_t * rwlock)1133 ldap_pvt_thread_rdwr_wtrylock( ldap_pvt_thread_rdwr_t *rwlock )
1134 {
1135           check_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_wtrylock" );
1136           return ldap_int_thread_rdwr_wtrylock( WRAPPED( rwlock ) );
1137 }
1138 
1139 int
ldap_pvt_thread_rdwr_wunlock(ldap_pvt_thread_rdwr_t * rwlock)1140 ldap_pvt_thread_rdwr_wunlock( ldap_pvt_thread_rdwr_t *rwlock )
1141 {
1142           int rc;
1143           check_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_wunlock" );
1144           rc = ldap_int_thread_rdwr_wunlock( WRAPPED( rwlock ) );
1145           ERROR_IF( rc, "ldap_pvt_thread_rdwr_wunlock" );
1146           return rc;
1147 }
1148 
1149 #if defined(LDAP_RDWR_DEBUG) && !defined(LDAP_THREAD_HAVE_RDWR)
1150 
1151 int
ldap_pvt_thread_rdwr_readers(ldap_pvt_thread_rdwr_t * rwlock)1152 ldap_pvt_thread_rdwr_readers( ldap_pvt_thread_rdwr_t *rwlock )
1153 {
1154           check_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_readers" );
1155           return ldap_int_thread_rdwr_readers( WRAPPED( rwlock ) );
1156 }
1157 
1158 int
ldap_pvt_thread_rdwr_writers(ldap_pvt_thread_rdwr_t * rwlock)1159 ldap_pvt_thread_rdwr_writers( ldap_pvt_thread_rdwr_t *rwlock )
1160 {
1161           check_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_writers" );
1162           return ldap_int_thread_rdwr_writers( WRAPPED( rwlock ) );
1163 }
1164 
1165 int
ldap_pvt_thread_rdwr_active(ldap_pvt_thread_rdwr_t * rwlock)1166 ldap_pvt_thread_rdwr_active( ldap_pvt_thread_rdwr_t *rwlock )
1167 {
1168           check_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_active" );
1169           return ldap_int_thread_rdwr_active( WRAPPED( rwlock ) );
1170 }
1171 
1172 #endif /* LDAP_RDWR_DEBUG && !LDAP_THREAD_HAVE_RDWR */
1173 
1174 
1175 /* Some wrappers for LDAP_THREAD_POOL_IMPLEMENTATION: */
1176 #ifdef LDAP_THREAD_POOL_IMPLEMENTATION
1177 
1178 int
ldap_pvt_thread_pool_init(ldap_pvt_thread_pool_t * tpool,int max_threads,int max_pending)1179 ldap_pvt_thread_pool_init(
1180           ldap_pvt_thread_pool_t *tpool,
1181           int max_threads,
1182           int max_pending )
1183 {
1184           int rc;
1185           if( !options_done )
1186                     get_options();
1187           ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_init" );
1188           rc = ldap_int_thread_pool_init( tpool, max_threads, max_pending );
1189           if( rc ) {
1190                     ERROR( rc, "ldap_pvt_thread_pool_init" );
1191           } else {
1192                     adjust_count( Idx_tpool, +1 );
1193           }
1194           return rc;
1195 }
1196 
1197 int
ldap_pvt_thread_pool_submit(ldap_pvt_thread_pool_t * tpool,ldap_pvt_thread_start_t * start_routine,void * arg)1198 ldap_pvt_thread_pool_submit(
1199           ldap_pvt_thread_pool_t *tpool,
1200           ldap_pvt_thread_start_t *start_routine, void *arg )
1201 {
1202           int rc, has_pool;
1203           ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_submit" );
1204           has_pool = (tpool && *tpool);
1205           rc = ldap_int_thread_pool_submit( tpool, start_routine, arg );
1206           if( has_pool )
1207                     ERROR_IF( rc, "ldap_pvt_thread_pool_submit" );
1208           return rc;
1209 }
1210 
1211 int
ldap_pvt_thread_pool_maxthreads(ldap_pvt_thread_pool_t * tpool,int max_threads)1212 ldap_pvt_thread_pool_maxthreads(
1213           ldap_pvt_thread_pool_t *tpool,
1214           int max_threads )
1215 {
1216           ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_maxthreads" );
1217           return ldap_int_thread_pool_maxthreads( tpool, max_threads );
1218 }
1219 
1220 int
ldap_pvt_thread_pool_backload(ldap_pvt_thread_pool_t * tpool)1221 ldap_pvt_thread_pool_backload( ldap_pvt_thread_pool_t *tpool )
1222 {
1223           ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_backload" );
1224           return ldap_int_thread_pool_backload( tpool );
1225 }
1226 
1227 int
ldap_pvt_thread_pool_destroy(ldap_pvt_thread_pool_t * tpool,int run_pending)1228 ldap_pvt_thread_pool_destroy( ldap_pvt_thread_pool_t *tpool, int run_pending )
1229 {
1230           int rc, has_pool;
1231           ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_destroy" );
1232           has_pool = (tpool && *tpool);
1233           rc = ldap_int_thread_pool_destroy( tpool, run_pending );
1234           if( has_pool ) {
1235                     if( rc ) {
1236                               ERROR( rc, "ldap_pvt_thread_pool_destroy" );
1237                     } else {
1238                               adjust_count( Idx_tpool, -1 );
1239                     }
1240           }
1241           return rc;
1242 }
1243 
1244 int
ldap_pvt_thread_pool_close(ldap_pvt_thread_pool_t * tpool,int run_pending)1245 ldap_pvt_thread_pool_close( ldap_pvt_thread_pool_t *tpool, int run_pending )
1246 {
1247           int rc, has_pool;
1248           ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_close" );
1249           has_pool = (tpool && *tpool);
1250           rc = ldap_int_thread_pool_close( tpool, run_pending );
1251           if( has_pool && rc ) {
1252                     ERROR( rc, "ldap_pvt_thread_pool_close" );
1253           }
1254           return rc;
1255 }
1256 
1257 int
ldap_pvt_thread_pool_free(ldap_pvt_thread_pool_t * tpool)1258 ldap_pvt_thread_pool_free( ldap_pvt_thread_pool_t *tpool )
1259 {
1260           int rc, has_pool;
1261           ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_free" );
1262           has_pool = (tpool && *tpool);
1263           rc = ldap_int_thread_pool_free( tpool );
1264           if( has_pool ) {
1265                     if( rc ) {
1266                               ERROR( rc, "ldap_pvt_thread_pool_free" );
1267                     } else {
1268                               adjust_count( Idx_tpool, -1 );
1269                     }
1270           }
1271           return rc;
1272 }
1273 
1274 int
ldap_pvt_thread_pool_pause(ldap_pvt_thread_pool_t * tpool)1275 ldap_pvt_thread_pool_pause( ldap_pvt_thread_pool_t *tpool )
1276 {
1277           ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_pause" );
1278           return ldap_int_thread_pool_pause( tpool );
1279 }
1280 
1281 int
ldap_pvt_thread_pool_resume(ldap_pvt_thread_pool_t * tpool)1282 ldap_pvt_thread_pool_resume( ldap_pvt_thread_pool_t *tpool )
1283 {
1284           ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_resume" );
1285           return ldap_int_thread_pool_resume( tpool );
1286 }
1287 
1288 int
ldap_pvt_thread_pool_getkey(void * xctx,void * key,void ** data,ldap_pvt_thread_pool_keyfree_t ** kfree)1289 ldap_pvt_thread_pool_getkey(
1290           void *xctx,
1291           void *key,
1292           void **data,
1293           ldap_pvt_thread_pool_keyfree_t **kfree )
1294 {
1295 #if 0 /* Function is used by ch_free() via slap_sl_contxt() in slapd */
1296           ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_getkey" );
1297 #endif
1298           return ldap_int_thread_pool_getkey( xctx, key, data, kfree );
1299 }
1300 
1301 int
ldap_pvt_thread_pool_setkey(void * xctx,void * key,void * data,ldap_pvt_thread_pool_keyfree_t * kfree,void ** olddatap,ldap_pvt_thread_pool_keyfree_t ** oldkfreep)1302 ldap_pvt_thread_pool_setkey(
1303           void *xctx,
1304           void *key,
1305           void *data,
1306           ldap_pvt_thread_pool_keyfree_t *kfree,
1307           void **olddatap,
1308           ldap_pvt_thread_pool_keyfree_t **oldkfreep )
1309 {
1310           int rc;
1311           ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_setkey" );
1312           rc = ldap_int_thread_pool_setkey(
1313                     xctx, key, data, kfree, olddatap, oldkfreep );
1314           ERROR_IF( rc, "ldap_pvt_thread_pool_setkey" );
1315           return rc;
1316 }
1317 
1318 void
ldap_pvt_thread_pool_purgekey(void * key)1319 ldap_pvt_thread_pool_purgekey( void *key )
1320 {
1321           ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_purgekey" );
1322           ldap_int_thread_pool_purgekey( key );
1323 }
1324 
1325 void *
ldap_pvt_thread_pool_context(void)1326 ldap_pvt_thread_pool_context( void )
1327 {
1328 #if 0 /* Function is used by ch_free() via slap_sl_contxt() in slapd */
1329           ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_context" );
1330 #endif
1331           return ldap_int_thread_pool_context();
1332 }
1333 
1334 void
ldap_pvt_thread_pool_context_reset(void * vctx)1335 ldap_pvt_thread_pool_context_reset( void *vctx )
1336 {
1337           ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_context_reset" );
1338           ldap_int_thread_pool_context_reset( vctx );
1339 }
1340 
1341 #endif /* LDAP_THREAD_POOL_IMPLEMENTATION */
1342 
1343 #endif /* LDAP_THREAD_DEBUG */
1344