Back to index

openldap  2.4.31
thr_debug.c
Go to the documentation of this file.
00001 /* thr_debug.c - wrapper around the chosen thread wrapper, for debugging. */
00002 /* $OpenLDAP$ */
00003 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
00004  *
00005  * Copyright 2005-2012 The OpenLDAP Foundation.
00006  * All rights reserved.
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted only as authorized by the OpenLDAP
00010  * Public License.
00011  *
00012  * A copy of this license is available in file LICENSE in the
00013  * top-level directory of the distribution or, alternatively, at
00014  * <http://www.OpenLDAP.org/license.html>.
00015  */
00016 
00017 /*
00018  * This package provides several types of thread operation debugging:
00019  *
00020  * - Check the results of operations on threads, mutexes, condition
00021  *   variables and read/write locks.  Also check some thread pool
00022  *   operations, but not those for which failure can happen in normal
00023  *   slapd operation.
00024  *
00025  * - Wrap those types except threads and pools in structs with state
00026  *   information, and check that on all operations:
00027  *
00028  *   + Check that the resources are initialized and are only used at
00029  *     their original address (i.e. not realloced or copied).
00030  *
00031  *   + Check the owner (thread ID) on mutex operations.
00032  *
00033  *   + Optionally allocate a reference to a byte of dummy memory.
00034  *     This lets malloc debuggers see some incorrect use as memory
00035  *     leaks, access to freed memory, etc.
00036  *
00037  * - Print an error message and by default abort() upon errors.
00038  *
00039  * - Print a count of leaked thread resources after cleanup.
00040  *
00041  * Compile-time (./configure) setup:  Macros defined in CPPFLAGS.
00042  *
00043  *   LDAP_THREAD_DEBUG or LDAP_THREAD_DEBUG=2
00044  *      Enables debugging, but value & 2 turns off type wrapping.
00045  *
00046  *   LDAP_UINTPTR_T=integer type to hold pointers, preferably unsigned.
00047  *      Used by dummy memory option "scramble". Default = unsigned long.
00048  *
00049  *   LDAP_DEBUG_THREAD_NONE = initializer for a "no thread" thread ID.
00050  *
00051  *   In addition, you may need to set up an implementation-specific way
00052  *      to enable whatever error checking your thread library provides.
00053  *      Currently only implemented for Posix threads (pthreads), where
00054  *      you may need to define LDAP_INT_THREAD_MUTEXATTR.  The default
00055  *      is PTHREAD_MUTEX_ERRORCHECK, or PTHREAD_MUTEX_ERRORCHECK_NP for
00056  *      Linux threads.  See pthread_mutexattr_settype(3).
00057  *
00058  * Run-time configuration:
00059  *
00060  *  Memory debugging tools:
00061  *   Tools that report uninitialized memory accesses should disable
00062  *   such warnings about the function debug_already_initialized().
00063  *   Alternatively, include "noreinit" (below) in $LDAP_THREAD_DEBUG.
00064  *
00065  *  Environment variable $LDAP_THREAD_DEBUG:
00066  *   The variable may contain a comma- or space-separated option list.
00067  *   Options:
00068  *      off      - Disable this package.  (It still slows things down).
00069  *      tracethreads - Report create/join/exit/kill of threads.
00070  *      noabort  - Do not abort() on errors.
00071  *      noerror  - Do not report errors.  Implies noabort.
00072  *      nocount  - Do not report counts of unreleased resources.
00073  *      nosync   - Disable tests that use synchronizaion and thus
00074  *                 clearly affect thread scheduling:
00075  *                 Implies nocount, and cancels threadID if that is set.
00076  *                 Note that if you turn on tracethreads or malloc
00077  *                 debugging, these also use library calls which may
00078  *                 affect thread scheduling (fprintf and malloc).
00079  *   The following options do not apply if type wrapping is disabled:
00080  *      nomem    - Do not check memory operations.
00081  *                 Implies noreinit,noalloc.
00082  *      noreinit - Do not catch reinitialization of existing resources.
00083  *                 (That test accesses uninitialized memory).
00084  *      threadID - Trace thread IDs.  Currently mostly useless.
00085  *     Malloc debugging -- allocate dummy memory for initialized
00086  *     resources, so malloc debuggers will report them as memory leaks:
00087  *      noalloc  - Default.  Do not allocate dummy memory.
00088  *      alloc    - Store a pointer to dummy memory.   However, leak
00089  *                 detectors might not catch unreleased resources in
00090  *                 global variables.
00091  *      scramble - Store bitwise complement of dummy memory pointer.
00092  *                 That never escapes memory leak detectors -
00093  *                 but detection while the program is running will
00094  *                 report active resources as leaks.  Do not
00095  *                 use this if a garbage collector is in use:-)
00096  *      adjptr   - Point to end of dummy memory.
00097  *                 Purify reports these as "potential leaks" (PLK).
00098  *                 I have not checked other malloc debuggers.
00099  */
00100 
00101 #include "portable.h"
00102 
00103 #if defined( LDAP_THREAD_DEBUG )
00104 
00105 #include <stdio.h>
00106 #include <ac/errno.h>
00107 #include <ac/stdlib.h>
00108 #include <ac/string.h>
00109 
00110 #include "ldap_pvt_thread.h" /* Get the thread interface */
00111 #define LDAP_THREAD_IMPLEMENTATION
00112 #define LDAP_THREAD_DEBUG_IMPLEMENTATION
00113 #define LDAP_THREAD_RDWR_IMPLEMENTATION
00114 #define LDAP_THREAD_POOL_IMPLEMENTATION
00115 #include "ldap_thr_debug.h"  /* Get the underlying implementation */
00116 
00117 #ifndef LDAP_THREAD_DEBUG_WRAP
00118 #undef LDAP_THREAD_DEBUG_THREAD_ID
00119 #elif !defined LDAP_THREAD_DEBUG_THREAD_ID
00120 #define       LDAP_THREAD_DEBUG_THREAD_ID 1
00121 #endif
00122 
00123 /* Use native malloc - the OpenLDAP wrappers may defeat malloc debuggers */
00124 #undef malloc
00125 #undef calloc
00126 #undef realloc
00127 #undef free
00128 
00129 
00130 /* Options from environment variable $LDAP_THREAD_DEBUG */
00131 enum { Count_no = 0, Count_yes, Count_reported, Count_reported_more };
00132 static int count = Count_yes;
00133 #ifdef LDAP_THREAD_DEBUG_WRAP
00134 enum { Wrap_noalloc, Wrap_alloc, Wrap_scramble, Wrap_adjptr };
00135 static int wraptype = Wrap_noalloc, wrap_offset, unwrap_offset;
00136 static int nomem, noreinit;
00137 #endif
00138 #if LDAP_THREAD_DEBUG_THREAD_ID +0
00139 static int threadID;
00140 #else
00141 enum { threadID = 0 };
00142 #endif
00143 static int nodebug, noabort, noerror, nosync, tracethreads;
00144 static int wrap_threads;
00145 static int options_done;
00146 
00147 
00148 /* ldap_pvt_thread_initialize() called, ldap_pvt_thread_destroy() not called */
00149 static int threading_enabled;
00150 
00151 
00152 /* Resource counts */
00153 enum {
00154        Idx_unexited_thread, Idx_unjoined_thread, Idx_locked_mutex,
00155        Idx_mutex, Idx_cond, Idx_rdwr, Idx_tpool, Idx_max
00156 };
00157 static int resource_counts[Idx_max];
00158 static const char *const resource_names[] = {
00159        "unexited threads", "unjoined threads", "locked mutexes",
00160        "mutexes", "conds", "rdwrs", "thread pools"
00161 };
00162 static ldap_int_thread_mutex_t resource_mutexes[Idx_max];
00163 
00164 
00165 /* Hide pointers from malloc debuggers. */
00166 #define SCRAMBLE(ptr) (~(LDAP_UINTPTR_T) (ptr))
00167 #define UNSCRAMBLE_usagep(num) ((ldap_debug_usage_info_t *) ~(num))
00168 #define UNSCRAMBLE_dummyp(num) ((unsigned char *) ~(num))
00169 
00170 
00171 #define WARN(var, msg)   (warn (__FILE__, __LINE__, (msg), #var, (var)))
00172 #define WARN_IF(rc, msg) {if (rc) warn (__FILE__, __LINE__, (msg), #rc, (rc));}
00173 
00174 #define ERROR(var, msg) { \
00175        if (!noerror) { \
00176               errmsg(__FILE__, __LINE__, (msg), #var, (var)); \
00177               if( !noabort ) abort(); \
00178        } \
00179 }
00180 
00181 #define ERROR_IF(rc, msg) { \
00182        if (!noerror) { \
00183               int rc_ = (rc); \
00184               if (rc_) { \
00185                      errmsg(__FILE__, __LINE__, (msg), #rc, rc_); \
00186                      if( !noabort ) abort(); \
00187               } \
00188        } \
00189 }
00190 
00191 #ifdef LDAP_THREAD_DEBUG_WRAP
00192 #define MEMERROR_IF(rc, msg, mem_act) { \
00193        if (!noerror) { \
00194               int rc_ = (rc); \
00195               if (rc_) { \
00196                      errmsg(__FILE__, __LINE__, (msg), #rc, rc_); \
00197                      if( wraptype != Wrap_noalloc ) { mem_act; } \
00198                      if( !noabort ) abort(); \
00199               } \
00200        } \
00201 }
00202 #endif /* LDAP_THREAD_DEBUG_WRAP */
00203 
00204 #if 0
00205 static void
00206 warn( const char *file, int line, const char *msg, const char *var, int val )
00207 {
00208        fprintf( stderr,
00209               (strpbrk( var, "!=" )
00210                ? "%s:%d: %s warning: %s\n"
00211                : "%s:%d: %s warning: %s is %d\n"),
00212               file, line, msg, var, val );
00213 }
00214 #endif
00215 
00216 static void
00217 errmsg( const char *file, int line, const char *msg, const char *var, int val )
00218 {
00219        fprintf( stderr,
00220               (strpbrk( var, "!=" )
00221                ? "%s:%d: %s error: %s\n"
00222                : "%s:%d: %s error: %s is %d\n"),
00223               file, line, msg, var, val );
00224 }
00225 
00226 static void
00227 count_resource_leaks( void )
00228 {
00229        int i, j;
00230        char errbuf[200];
00231        if( count == Count_yes ) {
00232               count = Count_reported;
00233 #if 0 /* Could break if there are still threads after atexit */
00234               for( i = j = 0; i < Idx_max; i++ )
00235                      j |= ldap_int_thread_mutex_destroy( &resource_mutexes[i] );
00236               WARN_IF( j, "ldap_debug_thread_destroy:mutexes" );
00237 #endif
00238               for( i = j = 0; i < Idx_max; i++ )
00239                      if( resource_counts[i] )
00240                             j += sprintf( errbuf + j, ", %d %s",
00241                                    resource_counts[i], resource_names[i] );
00242               if( j )
00243                      fprintf( stderr, "== thr_debug: Leaked%s. ==\n", errbuf + 1 );
00244        }
00245 }
00246 
00247 static void
00248 get_options( void )
00249 {
00250        static const struct option_info_s {
00251               const char    *name;
00252               int           *var, val;
00253        } option_info[] = {
00254               { "off",        &nodebug,  1 },
00255               { "noabort",    &noabort,  1 },
00256               { "noerror",    &noerror,  1 },
00257               { "nocount",    &count,    Count_no },
00258               { "nosync",     &nosync,   1 },
00259 #if LDAP_THREAD_DEBUG_THREAD_ID +0
00260               { "threadID",   &threadID, 1 },
00261 #endif
00262 #ifdef LDAP_THREAD_DEBUG_WRAP
00263               { "nomem",      &nomem,    1 },
00264               { "noreinit",   &noreinit, 1 },
00265               { "noalloc",    &wraptype, Wrap_noalloc },
00266               { "alloc",      &wraptype, Wrap_alloc },
00267               { "adjptr",     &wraptype, Wrap_adjptr },
00268               { "scramble", &wraptype, Wrap_scramble },
00269 #endif
00270               { "tracethreads", &tracethreads, 1 },
00271               { NULL, NULL, 0 }
00272        };
00273        const char *s = getenv( "LDAP_THREAD_DEBUG" );
00274        if( s != NULL ) {
00275               while( *(s += strspn( s, ", \t\r\n" )) != '\0' ) {
00276                      size_t optlen = strcspn( s, ", \t\r\n" );
00277                      const struct option_info_s *oi = option_info;
00278                      while( oi->name &&
00279                                (strncasecmp( oi->name, s, optlen ) || oi->name[optlen]) )
00280                             oi++;
00281                      if( oi->name )
00282                             *oi->var = oi->val;
00283                      else
00284                             fprintf( stderr,
00285                                    "== thr_debug: Unknown $%s option '%.*s' ==\n",
00286                                    "LDAP_THREAD_DEBUG", (int) optlen, s );
00287                      s += optlen;
00288               }
00289        }
00290        if( nodebug ) {
00291               tracethreads = 0;
00292               nosync = noerror = 1;
00293        }
00294        if( nosync )
00295               count = Count_no;
00296        if( noerror )
00297               noabort = 1;
00298 #if LDAP_THREAD_DEBUG_THREAD_ID +0
00299        if( nosync )
00300               threadID = 0;
00301 #endif
00302 #ifdef LDAP_THREAD_DEBUG_WRAP
00303        if( noerror )
00304               nomem = 1;
00305        if( !nomem ) {
00306               static const ldap_debug_usage_info_t usage;
00307               if( sizeof(LDAP_UINTPTR_T) < sizeof(unsigned char *)
00308                      || sizeof(LDAP_UINTPTR_T) < sizeof(ldap_debug_usage_info_t *)
00309                      || UNSCRAMBLE_usagep( SCRAMBLE( &usage ) ) != &usage
00310                      || UNSCRAMBLE_dummyp( SCRAMBLE( (unsigned char *) 0 ) ) )
00311               {
00312                      fputs( "== thr_debug: Memory checks unsupported, "
00313                             "adding nomem to $LDAP_THREAD_DEBUG ==\n", stderr );
00314                      nomem = 1;
00315               }
00316        }
00317        if( nomem ) {
00318               noreinit = 1;
00319               wraptype = Wrap_noalloc;
00320        }
00321        unwrap_offset = -(wrap_offset = (wraptype == Wrap_adjptr));
00322 #endif
00323        wrap_threads = (tracethreads || threadID || count);
00324        options_done = 1;
00325 }
00326 
00327 
00328 #ifndef LDAP_THREAD_DEBUG_WRAP
00329 
00330 #define       WRAPPED(ptr)                (ptr)
00331 #define       GET_OWNER(ptr)                     0
00332 #define       SET_OWNER(ptr, thread)      ((void) 0)
00333 #define       RESET_OWNER(ptr)            ((void) 0)
00334 #define       ASSERT_OWNER(ptr, msg)      ((void) 0)
00335 #define       ASSERT_NO_OWNER(ptr, msg) ((void) 0)
00336 
00337 #define init_usage(ptr, msg)       ((void) 0)
00338 #define check_usage(ptr, msg)      ((void) 0)
00339 #define destroy_usage(ptr)         ((void) 0)
00340 
00341 #else /* LDAP_THREAD_DEBUG_WRAP */
00342 
00343 /* Specialize this if the initializer is not appropriate. */
00344 /* The ASSERT_NO_OWNER() definition may also need an override. */
00345 #ifndef LDAP_DEBUG_THREAD_NONE
00346 #define       LDAP_DEBUG_THREAD_NONE { -1 } /* "no thread" ldap_int_thread_t value */
00347 #endif
00348 
00349 static const ldap_int_thread_t ldap_debug_thread_none = LDAP_DEBUG_THREAD_NONE;
00350 
00351 #define THREAD_MUTEX_OWNER(mutex) \
00352        ldap_int_thread_equal( (mutex)->owner, ldap_int_thread_self() )
00353 
00354 void
00355 ldap_debug_thread_assert_mutex_owner(
00356        const char *file,
00357        int line,
00358        const char *msg,
00359        ldap_pvt_thread_mutex_t *mutex )
00360 {
00361        if( !(noerror || THREAD_MUTEX_OWNER( mutex )) ) {
00362               errmsg( file, line, msg, "ASSERT_MUTEX_OWNER", 0 );
00363               if( !noabort ) abort();
00364        }
00365 }
00366 
00367 #define       WRAPPED(ptr)                (&(ptr)->wrapped)
00368 #define       GET_OWNER(ptr)                     ((ptr)->owner)
00369 #define       SET_OWNER(ptr, thread)      ((ptr)->owner = (thread))
00370 #define       RESET_OWNER(ptr)            ((ptr)->owner = ldap_debug_thread_none)
00371 #define       ASSERT_OWNER(ptr, msg)      ERROR_IF( !THREAD_MUTEX_OWNER( ptr ), msg )
00372 #ifndef       ASSERT_NO_OWNER
00373 #define       ASSERT_NO_OWNER(ptr, msg) ERROR_IF( \
00374        !ldap_int_thread_equal( (ptr)->owner, ldap_debug_thread_none ), msg )
00375 #endif
00376 
00377 /* Try to provoke memory access error (for malloc debuggers) */
00378 #define PEEK(mem) {if (-*(volatile const unsigned char *)(mem)) debug_noop();}
00379 
00380 static void debug_noop( void );
00381 static int debug_already_initialized( const ldap_debug_usage_info_t *usage );
00382 
00383 /* Name used for clearer error message */
00384 #define IS_COPY_OR_MOVED(usage) ((usage)->self != SCRAMBLE( usage ))
00385 
00386 #define DUMMY_ADDR(usage) \
00387        (wraptype == Wrap_scramble \
00388         ? UNSCRAMBLE_dummyp( (usage)->mem.num ) \
00389         : (usage)->mem.ptr + unwrap_offset)
00390 
00391 /* Mark resource as initialized */
00392 static void
00393 init_usage( ldap_debug_usage_info_t *usage, const char *msg )
00394 {
00395        if( !options_done )
00396               get_options();
00397        if( !nomem ) {
00398               if( !noreinit ) {
00399                      MEMERROR_IF( debug_already_initialized( usage ), msg, {
00400                             /* Provoke malloc debuggers */
00401                             unsigned char *dummy = DUMMY_ADDR( usage );
00402                             PEEK( dummy );
00403                             free( dummy );
00404                             free( dummy );
00405                      } );
00406               }
00407               if( wraptype != Wrap_noalloc ) {
00408                      unsigned char *dummy = malloc( 1 );
00409                      assert( dummy != NULL );
00410                      if( wraptype == Wrap_scramble ) {
00411                             usage->mem.num = SCRAMBLE( dummy );
00412                             /* Verify that ptr<->integer casts work on this host */
00413                             assert( UNSCRAMBLE_dummyp( usage->mem.num ) == dummy );
00414                      } else {
00415                             usage->mem.ptr = dummy + wrap_offset;
00416                      }
00417               }
00418        } else {
00419               /* Unused, but set for readability in debugger */
00420               usage->mem.ptr = NULL;
00421        }
00422        usage->self = SCRAMBLE( usage );   /* If nomem, only for debugger */
00423        usage->magic = ldap_debug_magic;
00424        usage->state = ldap_debug_state_inited;
00425 }
00426 
00427 /* Check that resource is initialized and not copied/realloced */
00428 static void
00429 check_usage( const ldap_debug_usage_info_t *usage, const char *msg )
00430 {
00431        enum { Is_destroyed = 1 };  /* Name used for clearer error message */
00432 
00433        if( usage->magic != ldap_debug_magic ) {
00434               ERROR( usage->magic, msg );
00435               return;
00436        }
00437        switch( usage->state ) {
00438        case ldap_debug_state_destroyed:
00439               MEMERROR_IF( Is_destroyed, msg, {
00440                      PEEK( DUMMY_ADDR( usage ) );
00441               } );
00442               break;
00443        default:
00444               ERROR( usage->state, msg );
00445               break;
00446        case ldap_debug_state_inited:
00447               if( !nomem ) {
00448                      MEMERROR_IF( IS_COPY_OR_MOVED( usage ), msg, {
00449                             PEEK( DUMMY_ADDR( usage ) );
00450                             PEEK( UNSCRAMBLE_usagep( usage->self ) );
00451                      } );
00452               }
00453               break;
00454        }
00455 }
00456 
00457 /* Mark resource as destroyed. */
00458 /* Does not check for errors, call check_usage()/init_usage() first. */
00459 static void
00460 destroy_usage( ldap_debug_usage_info_t *usage )
00461 {
00462        if( usage->state == ldap_debug_state_inited ) {
00463               if( wraptype != Wrap_noalloc ) {
00464                      free( DUMMY_ADDR( usage ) );
00465                      /* Do not reset the DUMMY_ADDR, leave it for malloc debuggers
00466                       * in case the resource is used after it is freed. */
00467               }
00468               usage->state = ldap_debug_state_destroyed;
00469        }
00470 }
00471 
00472 /* Define these after they are used, so they are hopefully not inlined */
00473 
00474 static void
00475 debug_noop( void )
00476 {
00477 }
00478 
00479 /*
00480  * Valid programs access uninitialized memory here unless "noreinit".
00481  *
00482  * Returns true if the resource is initialized and not copied/realloced.
00483  */
00484 LDAP_GCCATTR((noinline))
00485 static int
00486 debug_already_initialized( const ldap_debug_usage_info_t *usage )
00487 {
00488        /*
00489         * 'ret' keeps the Valgrind warning "Conditional jump or move
00490         * depends on uninitialised value(s)" _inside_ this function.
00491         */
00492        volatile int ret = 0;
00493        if( usage->state == ldap_debug_state_inited )
00494               if( !IS_COPY_OR_MOVED( usage ) )
00495                if( usage->magic == ldap_debug_magic )
00496                             ret = 1;
00497        return ret;
00498 }
00499 
00500 #endif /* LDAP_THREAD_DEBUG_WRAP */
00501 
00502 
00503 #if !(LDAP_THREAD_DEBUG_THREAD_ID +0)
00504 
00505 typedef void ldap_debug_thread_t;
00506 #define init_thread_info()  {}
00507 #define with_thread_info_lock(statements) { statements; }
00508 #define thread_info_detached(t)    0
00509 #define add_thread_info(msg, thr, det)    ((void) 0)
00510 #define remove_thread_info(tinfo, msg)    ((void) 0)
00511 #define get_thread_info(thread, msg)      NULL
00512 
00513 #else /* LDAP_THREAD_DEBUG_THREAD_ID */
00514 
00515 /*
00516  * Thread ID tracking.  Currently acieves little.
00517  * Should be either expanded or deleted.
00518  */
00519 
00520 /*
00521  * Array of threads.  Used instead of making ldap_pvt_thread_t a wrapper
00522  * around ldap_int_thread_t, which would slow down ldap_pvt_thread_self().
00523  */
00524 typedef struct {
00525        ldap_pvt_thread_t           wrapped;
00526        ldap_debug_usage_info_t     usage;
00527        int                         detached;
00528        int                         idx;
00529 } ldap_debug_thread_t;
00530 
00531 static ldap_debug_thread_t      **thread_info;
00532 static unsigned int             thread_info_size, thread_info_used;
00533 static ldap_int_thread_mutex_t  thread_info_mutex;
00534 
00535 #define init_thread_info() { \
00536        if( threadID ) { \
00537               int mutex_init_rc = ldap_int_thread_mutex_init( &thread_info_mutex ); \
00538               assert( mutex_init_rc == 0 ); \
00539        } \
00540 }
00541 
00542 #define with_thread_info_lock(statements) { \
00543        int rc_wtl_ = ldap_int_thread_mutex_lock( &thread_info_mutex ); \
00544        assert( rc_wtl_ == 0 ); \
00545        { statements; } \
00546        rc_wtl_ = ldap_int_thread_mutex_unlock( &thread_info_mutex ); \
00547        assert( rc_wtl_ == 0 ); \
00548 }
00549 
00550 #define thread_info_detached(t) ((t)->detached)
00551 
00552 static void
00553 add_thread_info(
00554        const char *msg,
00555        const ldap_pvt_thread_t *thread,
00556        int detached )
00557 {
00558        ldap_debug_thread_t *t;
00559 
00560        if( thread_info_used >= thread_info_size ) {
00561               unsigned int more = thread_info_size + 8;
00562               unsigned int new_size = thread_info_size + more;
00563 
00564               t = calloc( more, sizeof(ldap_debug_thread_t) );
00565               assert( t != NULL );
00566               thread_info = realloc( thread_info, new_size * sizeof(*thread_info) );
00567               assert( thread_info != NULL );
00568               do {
00569                      t->idx = thread_info_size;
00570                      thread_info[thread_info_size++] = t++;
00571               } while( thread_info_size < new_size );
00572        }
00573 
00574        t = thread_info[thread_info_used];
00575        init_usage( &t->usage, msg );
00576        t->wrapped = *thread;
00577        t->detached = detached;
00578        thread_info_used++;
00579 }
00580 
00581 static void
00582 remove_thread_info( ldap_debug_thread_t *t, const char *msg )
00583 {
00584               ldap_debug_thread_t *last;
00585               int idx;
00586               check_usage( &t->usage, msg );
00587               destroy_usage( &t->usage );
00588               idx = t->idx;
00589               assert( thread_info[idx] == t );
00590               last = thread_info[--thread_info_used];
00591               assert( last->idx == thread_info_used );
00592               (thread_info[idx]              = last)->idx = idx;
00593               (thread_info[thread_info_used] = t   )->idx = thread_info_used;
00594 }
00595 
00596 static ldap_debug_thread_t *
00597 get_thread_info( ldap_pvt_thread_t thread, const char *msg )
00598 {
00599        unsigned int i;
00600        ldap_debug_thread_t *t;
00601        for( i = 0; i < thread_info_used; i++ ) {
00602               if( ldap_pvt_thread_equal( thread, thread_info[i]->wrapped ) )
00603                      break;
00604        }
00605        ERROR_IF( i == thread_info_used, msg );
00606        t = thread_info[i];
00607        check_usage( &t->usage, msg );
00608        return t;
00609 }
00610 
00611 #endif /* LDAP_THREAD_DEBUG_THREAD_ID */
00612 
00613 
00614 static char *
00615 thread_name( char *buf, int bufsize, ldap_pvt_thread_t thread )
00616 {
00617        int i;
00618        --bufsize;
00619        if( bufsize > 2*sizeof(thread) )
00620               bufsize = 2*sizeof(thread);
00621        for( i = 0; i < bufsize; i += 2 )
00622               snprintf( buf+i, 3, "%02x", ((unsigned char *)&thread)[i/2] );
00623        return buf;
00624 }
00625 
00626 
00627 /* Add <adjust> (+/-1) to resource count <which> unless "nocount". */
00628 static void
00629 adjust_count( int which, int adjust )
00630 {
00631        int rc;
00632        switch( count ) {
00633        case Count_no:
00634               break;
00635        case Count_yes:
00636               rc = ldap_int_thread_mutex_lock( &resource_mutexes[which] );
00637               assert( rc == 0 );
00638               resource_counts[which] += adjust;
00639               rc = ldap_int_thread_mutex_unlock( &resource_mutexes[which] );
00640               assert( rc == 0 );
00641               break;
00642        case Count_reported:
00643               fputs( "== thr_debug: More thread activity after exit ==\n", stderr );
00644               count = Count_reported_more;
00645               /* FALL THROUGH */
00646        case Count_reported_more:
00647               /* Not used, but result might be inspected with debugger */
00648               /* (Hopefully threading is disabled by now...) */
00649               resource_counts[which] += adjust;
00650               break;
00651        }
00652 }
00653 
00654 
00655 /* Wrappers for LDAP_THREAD_IMPLEMENTATION: */
00656 
00657 /* Used instead of ldap_int_thread_initialize by ldap_pvt_thread_initialize */
00658 int
00659 ldap_debug_thread_initialize( void )
00660 {
00661        int i, rc, rc2;
00662        if( !options_done )
00663               get_options();
00664        ERROR_IF( threading_enabled, "ldap_debug_thread_initialize" );
00665        threading_enabled = 1;
00666        rc = ldap_int_thread_initialize();
00667        if( rc ) {
00668               ERROR( rc, "ldap_debug_thread_initialize:threads" );
00669               threading_enabled = 0;
00670        } else {
00671               init_thread_info();
00672               if( count != Count_no ) {
00673                      for( i = rc2 = 0; i < Idx_max; i++ )
00674                             rc2 |= ldap_int_thread_mutex_init( &resource_mutexes[i] );
00675                      assert( rc2 == 0 );
00676                      /* FIXME: Only for static libldap_r as in init.c? If so, why? */
00677                      atexit( count_resource_leaks );
00678               }
00679        }
00680        return rc;
00681 }
00682 
00683 /* Used instead of ldap_int_thread_destroy by ldap_pvt_thread_destroy */
00684 int
00685 ldap_debug_thread_destroy( void )
00686 {
00687        int rc;
00688        ERROR_IF( !threading_enabled, "ldap_debug_thread_destroy" );
00689        /* sleep(1) -- need to wait for thread pool to finish? */
00690        rc = ldap_int_thread_destroy();
00691        if( rc ) {
00692               ERROR( rc, "ldap_debug_thread_destroy:threads" );
00693        } else {
00694               threading_enabled = 0;
00695        }
00696        return rc;
00697 }
00698 
00699 int
00700 ldap_pvt_thread_set_concurrency( int n )
00701 {
00702        int rc;
00703        ERROR_IF( !threading_enabled, "ldap_pvt_thread_set_concurrency" );
00704        rc = ldap_int_thread_set_concurrency( n );
00705        ERROR_IF( rc, "ldap_pvt_thread_set_concurrency" );
00706        return rc;
00707 }
00708 
00709 int
00710 ldap_pvt_thread_get_concurrency( void )
00711 {
00712        int rc;
00713        ERROR_IF( !threading_enabled, "ldap_pvt_thread_get_concurrency" );
00714        rc = ldap_int_thread_get_concurrency();
00715        ERROR_IF( rc, "ldap_pvt_thread_get_concurrency" );
00716        return rc;
00717 }
00718 
00719 unsigned int
00720 ldap_pvt_thread_sleep( unsigned int interval )
00721 {
00722        int rc;
00723        ERROR_IF( !threading_enabled, "ldap_pvt_thread_sleep" );
00724        rc = ldap_int_thread_sleep( interval );
00725        ERROR_IF( rc, "ldap_pvt_thread_sleep" );
00726        return 0;
00727 }
00728 
00729 static void
00730 thread_exiting( const char *how, const char *msg )
00731 {
00732        ldap_pvt_thread_t thread;
00733 #if 0 /* Detached threads may exit after ldap_debug_thread_destroy(). */
00734        ERROR_IF( !threading_enabled, msg );
00735 #endif
00736        thread = ldap_pvt_thread_self();
00737        if( tracethreads ) {
00738               char buf[40];
00739               fprintf( stderr, "== thr_debug: %s thread %s ==\n",
00740                      how, thread_name( buf, sizeof(buf), thread ) );
00741        }
00742        if( threadID ) {
00743               with_thread_info_lock({
00744                      ldap_debug_thread_t *t = get_thread_info( thread, msg );
00745                      if( thread_info_detached( t ) )
00746                             remove_thread_info( t, msg );
00747               });
00748        }
00749        adjust_count( Idx_unexited_thread, -1 );
00750 }
00751 
00752 void
00753 ldap_pvt_thread_exit( void *retval )
00754 {
00755        thread_exiting( "Exiting", "ldap_pvt_thread_exit" );
00756        ldap_int_thread_exit( retval );
00757 }
00758 
00759 typedef struct {
00760        void *(*start_routine)( void * );
00761        void *arg;
00762 } ldap_debug_thread_call_t;
00763 
00764 static void *
00765 ldap_debug_thread_wrapper( void *arg )
00766 {
00767        void *ret;
00768        ldap_debug_thread_call_t call = *(ldap_debug_thread_call_t *)arg;
00769        free( arg );
00770        ret = call.start_routine( call.arg );
00771        thread_exiting( "Returning from", "ldap_debug_thread_wrapper" );
00772        return ret;
00773 }
00774 
00775 int
00776 ldap_pvt_thread_create(
00777        ldap_pvt_thread_t *thread,
00778        int detach,
00779        void *(*start_routine)( void * ),
00780        void *arg )
00781 {
00782        int rc;
00783        if( !options_done )
00784               get_options();
00785        ERROR_IF( !threading_enabled, "ldap_pvt_thread_create" );
00786 
00787        if( wrap_threads ) {
00788               ldap_debug_thread_call_t *call = malloc(
00789                      sizeof( ldap_debug_thread_call_t ) );
00790               assert( call != NULL );
00791               call->start_routine = start_routine;
00792               call->arg = arg;
00793               start_routine = ldap_debug_thread_wrapper;
00794               arg = call;
00795        }
00796        if( threadID ) {
00797               with_thread_info_lock({
00798                      rc = ldap_int_thread_create( thread, detach, start_routine, arg );
00799                      if( rc == 0 )
00800                             add_thread_info( "ldap_pvt_thread_create", thread, detach );
00801               });
00802        } else {
00803               rc = ldap_int_thread_create( thread, detach, start_routine, arg );
00804        }
00805        if( rc ) {
00806               ERROR( rc, "ldap_pvt_thread_create" );
00807               if( wrap_threads )
00808                      free( arg );
00809        } else {
00810               if( tracethreads ) {
00811                      char buf[40], buf2[40];
00812                      fprintf( stderr,
00813                             "== thr_debug: Created thread %s%s from thread %s ==\n",
00814                             thread_name( buf, sizeof(buf), *thread ),
00815                             detach ? " (detached)" : "",
00816                             thread_name( buf2, sizeof(buf2), ldap_pvt_thread_self() ) );
00817               }
00818               adjust_count( Idx_unexited_thread, +1 );
00819               if( !detach )
00820                      adjust_count( Idx_unjoined_thread, +1 );
00821        }
00822        return rc;
00823 }
00824 
00825 int
00826 ldap_pvt_thread_join( ldap_pvt_thread_t thread, void **thread_return )
00827 {
00828        int rc;
00829        ldap_debug_thread_t *t = NULL;
00830        ERROR_IF( !threading_enabled, "ldap_pvt_thread_join" );
00831        if( tracethreads ) {
00832               char buf[40], buf2[40];
00833               fprintf( stderr, "== thr_debug: Joining thread %s in thread %s ==\n",
00834                      thread_name( buf, sizeof(buf), thread ),
00835                      thread_name( buf2, sizeof(buf2), ldap_pvt_thread_self() ) );
00836        }
00837        if( threadID )
00838               with_thread_info_lock( {
00839                      t = get_thread_info( thread, "ldap_pvt_thread_join" );
00840                      ERROR_IF( thread_info_detached( t ), "ldap_pvt_thread_join" );
00841               } );
00842        rc = ldap_int_thread_join( thread, thread_return );
00843        if( rc ) {
00844               ERROR( rc, "ldap_pvt_thread_join" );
00845        } else {
00846               if( threadID )
00847                      with_thread_info_lock(
00848                             remove_thread_info( t, "ldap_pvt_thread_join" ) );
00849               adjust_count( Idx_unjoined_thread, -1 );
00850        }
00851 
00852        return rc;
00853 }
00854 
00855 int
00856 ldap_pvt_thread_kill( ldap_pvt_thread_t thread, int signo )
00857 {
00858        int rc;
00859        ERROR_IF( !threading_enabled, "ldap_pvt_thread_kill" );
00860        if( tracethreads ) {
00861               char buf[40], buf2[40];
00862               fprintf( stderr,
00863                      "== thr_debug: Killing thread %s (sig %i) from thread %s ==\n",
00864                      thread_name( buf, sizeof(buf), thread ), signo,
00865                      thread_name( buf2, sizeof(buf2), ldap_pvt_thread_self() ) );
00866        }
00867        rc = ldap_int_thread_kill( thread, signo );
00868        ERROR_IF( rc, "ldap_pvt_thread_kill" );
00869        return rc;
00870 }
00871 
00872 int
00873 ldap_pvt_thread_yield( void )
00874 {
00875        int rc;
00876        ERROR_IF( !threading_enabled, "ldap_pvt_thread_yield" );
00877        rc = ldap_int_thread_yield();
00878        ERROR_IF( rc, "ldap_pvt_thread_yield" );
00879        return rc;
00880 }
00881 
00882 ldap_pvt_thread_t
00883 ldap_pvt_thread_self( void )
00884 {
00885 #if 0 /* Function is used by ch_free() via slap_sl_contxt() in slapd */
00886        ERROR_IF( !threading_enabled, "ldap_pvt_thread_self" );
00887 #endif
00888        return ldap_int_thread_self();
00889 }
00890 
00891 int
00892 ldap_pvt_thread_cond_init( ldap_pvt_thread_cond_t *cond )
00893 {
00894        int rc;
00895        init_usage( &cond->usage, "ldap_pvt_thread_cond_init" );
00896        rc = ldap_int_thread_cond_init( WRAPPED( cond ) );
00897        if( rc ) {
00898               ERROR( rc, "ldap_pvt_thread_cond_init" );
00899               destroy_usage( &cond->usage );
00900        } else {
00901               adjust_count( Idx_cond, +1 );
00902        }
00903        return rc;
00904 }
00905 
00906 int
00907 ldap_pvt_thread_cond_destroy( ldap_pvt_thread_cond_t *cond )
00908 {
00909        int rc;
00910        check_usage( &cond->usage, "ldap_pvt_thread_cond_destroy" );
00911        rc = ldap_int_thread_cond_destroy( WRAPPED( cond ) );
00912        if( rc ) {
00913               ERROR( rc, "ldap_pvt_thread_cond_destroy" );
00914        } else {
00915               destroy_usage( &cond->usage );
00916               adjust_count( Idx_cond, -1 );
00917        }
00918        return rc;
00919 }
00920 
00921 int
00922 ldap_pvt_thread_cond_signal( ldap_pvt_thread_cond_t *cond )
00923 {
00924        int rc;
00925        check_usage( &cond->usage, "ldap_pvt_thread_cond_signal" );
00926        rc = ldap_int_thread_cond_signal( WRAPPED( cond ) );
00927        ERROR_IF( rc, "ldap_pvt_thread_cond_signal" );
00928        return rc;
00929 }
00930 
00931 int
00932 ldap_pvt_thread_cond_broadcast( ldap_pvt_thread_cond_t *cond )
00933 {
00934        int rc;
00935        check_usage( &cond->usage, "ldap_pvt_thread_cond_broadcast" );
00936        rc = ldap_int_thread_cond_broadcast( WRAPPED( cond ) );
00937        ERROR_IF( rc, "ldap_pvt_thread_cond_broadcast" );
00938        return rc;
00939 }
00940 
00941 int
00942 ldap_pvt_thread_cond_wait(
00943        ldap_pvt_thread_cond_t *cond,
00944        ldap_pvt_thread_mutex_t *mutex )
00945 {
00946        int rc;
00947        ldap_int_thread_t owner;
00948        check_usage( &cond->usage, "ldap_pvt_thread_cond_wait:cond" );
00949        check_usage( &mutex->usage, "ldap_pvt_thread_cond_wait:mutex" );
00950        adjust_count( Idx_locked_mutex, -1 );
00951        owner = GET_OWNER( mutex );
00952        ASSERT_OWNER( mutex, "ldap_pvt_thread_cond_wait" );
00953        RESET_OWNER( mutex );
00954        rc = ldap_int_thread_cond_wait( WRAPPED( cond ), WRAPPED( mutex ) );
00955        ASSERT_NO_OWNER( mutex, "ldap_pvt_thread_cond_wait" );
00956        SET_OWNER( mutex, rc ? owner : ldap_int_thread_self() );
00957        adjust_count( Idx_locked_mutex, +1 );
00958        ERROR_IF( rc, "ldap_pvt_thread_cond_wait" );
00959        return rc;
00960 }
00961 
00962 int
00963 ldap_pvt_thread_mutex_init( ldap_pvt_thread_mutex_t *mutex )
00964 {
00965        int rc;
00966        init_usage( &mutex->usage, "ldap_pvt_thread_mutex_init" );
00967        rc = ldap_int_thread_mutex_init( WRAPPED( mutex ) );
00968        if( rc ) {
00969               ERROR( rc, "ldap_pvt_thread_mutex_init" );
00970               destroy_usage( &mutex->usage );
00971        } else {
00972               RESET_OWNER( mutex );
00973               adjust_count( Idx_mutex, +1 );
00974        }
00975        return rc;
00976 }
00977 
00978 int
00979 ldap_pvt_thread_mutex_destroy( ldap_pvt_thread_mutex_t *mutex )
00980 {
00981        int rc;
00982        check_usage( &mutex->usage, "ldap_pvt_thread_mutex_destroy" );
00983        ASSERT_NO_OWNER( mutex, "ldap_pvt_thread_mutex_destroy" );
00984        rc = ldap_int_thread_mutex_destroy( WRAPPED( mutex ) );
00985        if( rc ) {
00986               ERROR( rc, "ldap_pvt_thread_mutex_destroy" );
00987        } else {
00988               destroy_usage( &mutex->usage );
00989               RESET_OWNER( mutex );
00990               adjust_count( Idx_mutex, -1 );
00991        }
00992        return rc;
00993 }
00994 
00995 int
00996 ldap_pvt_thread_mutex_lock( ldap_pvt_thread_mutex_t *mutex )
00997 {
00998        int rc;
00999        check_usage( &mutex->usage, "ldap_pvt_thread_mutex_lock" );
01000        rc = ldap_int_thread_mutex_lock( WRAPPED( mutex ) );
01001        if( rc ) {
01002               ERROR_IF( rc, "ldap_pvt_thread_mutex_lock" );
01003        } else {
01004               ASSERT_NO_OWNER( mutex, "ldap_pvt_thread_mutex_lock" );
01005               SET_OWNER( mutex, ldap_int_thread_self() );
01006               adjust_count( Idx_locked_mutex, +1 );
01007        }
01008        return rc;
01009 }
01010 
01011 int
01012 ldap_pvt_thread_mutex_trylock( ldap_pvt_thread_mutex_t *mutex )
01013 {
01014        int rc;
01015        check_usage( &mutex->usage, "ldap_pvt_thread_mutex_trylock" );
01016        rc = ldap_int_thread_mutex_trylock( WRAPPED( mutex ) );
01017        if( rc == 0 ) {
01018               ASSERT_NO_OWNER( mutex, "ldap_pvt_thread_mutex_trylock" );
01019               SET_OWNER( mutex, ldap_int_thread_self() );
01020               adjust_count( Idx_locked_mutex, +1 );
01021        }
01022        return rc;
01023 }
01024 
01025 int
01026 ldap_pvt_thread_mutex_unlock( ldap_pvt_thread_mutex_t *mutex )
01027 {
01028        int rc;
01029        check_usage( &mutex->usage, "ldap_pvt_thread_mutex_unlock" );
01030        ASSERT_OWNER( mutex, "ldap_pvt_thread_mutex_unlock" );
01031        RESET_OWNER( mutex ); /* Breaks if this thread did not own the mutex */
01032        rc = ldap_int_thread_mutex_unlock( WRAPPED( mutex ) );
01033        if( rc ) {
01034               ERROR_IF( rc, "ldap_pvt_thread_mutex_unlock" );
01035        } else {
01036               adjust_count( Idx_locked_mutex, -1 );
01037        }
01038        return rc;
01039 }
01040 
01041 
01042 /* Wrappers for LDAP_THREAD_RDWR_IMPLEMENTATION: */
01043 
01044 int
01045 ldap_pvt_thread_rdwr_init( ldap_pvt_thread_rdwr_t *rwlock )
01046 {
01047        int rc;
01048        init_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_init" );
01049        rc = ldap_int_thread_rdwr_init( WRAPPED( rwlock ) );
01050        if( rc ) {
01051               ERROR( rc, "ldap_pvt_thread_rdwr_init" );
01052               destroy_usage( &rwlock->usage );
01053        } else {
01054               adjust_count( Idx_rdwr, +1 );
01055        }
01056        return rc;
01057 }
01058 
01059 int
01060 ldap_pvt_thread_rdwr_destroy( ldap_pvt_thread_rdwr_t *rwlock )
01061 {
01062        int rc;
01063        check_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_destroy" );
01064        rc = ldap_int_thread_rdwr_destroy( WRAPPED( rwlock ) );
01065        if( rc ) {
01066               ERROR( rc, "ldap_pvt_thread_rdwr_destroy" );
01067        } else {
01068               destroy_usage( &rwlock->usage );
01069               adjust_count( Idx_rdwr, -1 );
01070        }
01071        return rc;
01072 }
01073 
01074 int
01075 ldap_pvt_thread_rdwr_rlock( ldap_pvt_thread_rdwr_t *rwlock )
01076 {
01077        int rc;
01078        check_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_rlock" );
01079        rc = ldap_int_thread_rdwr_rlock( WRAPPED( rwlock ) );
01080        ERROR_IF( rc, "ldap_pvt_thread_rdwr_rlock" );
01081        return rc;
01082 }
01083 
01084 int
01085 ldap_pvt_thread_rdwr_rtrylock( ldap_pvt_thread_rdwr_t *rwlock )
01086 {
01087        check_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_rtrylock" );
01088        return ldap_int_thread_rdwr_rtrylock( WRAPPED( rwlock ) );
01089 }
01090 
01091 int
01092 ldap_pvt_thread_rdwr_runlock( ldap_pvt_thread_rdwr_t *rwlock )
01093 {
01094        int rc;
01095        check_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_runlock" );
01096        rc = ldap_int_thread_rdwr_runlock( WRAPPED( rwlock ) );
01097        ERROR_IF( rc, "ldap_pvt_thread_rdwr_runlock" );
01098        return rc;
01099 }
01100 
01101 int
01102 ldap_pvt_thread_rdwr_wlock( ldap_pvt_thread_rdwr_t *rwlock )
01103 {
01104        int rc;
01105        check_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_wlock" );
01106        rc = ldap_int_thread_rdwr_wlock( WRAPPED( rwlock ) );
01107        ERROR_IF( rc, "ldap_pvt_thread_rdwr_wlock" );
01108        return rc;
01109 }
01110 
01111 int
01112 ldap_pvt_thread_rdwr_wtrylock( ldap_pvt_thread_rdwr_t *rwlock )
01113 {
01114        check_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_wtrylock" );
01115        return ldap_int_thread_rdwr_wtrylock( WRAPPED( rwlock ) );
01116 }
01117 
01118 int
01119 ldap_pvt_thread_rdwr_wunlock( ldap_pvt_thread_rdwr_t *rwlock )
01120 {
01121        int rc;
01122        check_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_wunlock" );
01123        rc = ldap_int_thread_rdwr_wunlock( WRAPPED( rwlock ) );
01124        ERROR_IF( rc, "ldap_pvt_thread_rdwr_wunlock" );
01125        return rc;
01126 }
01127 
01128 #if defined(LDAP_RDWR_DEBUG) && !defined(LDAP_THREAD_HAVE_RDWR)
01129 
01130 int
01131 ldap_pvt_thread_rdwr_readers( ldap_pvt_thread_rdwr_t *rwlock )
01132 {
01133        check_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_readers" );
01134        return ldap_int_thread_rdwr_readers( WRAPPED( rwlock ) );
01135 }
01136 
01137 int
01138 ldap_pvt_thread_rdwr_writers( ldap_pvt_thread_rdwr_t *rwlock )
01139 {
01140        check_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_writers" );
01141        return ldap_int_thread_rdwr_writers( WRAPPED( rwlock ) );
01142 }
01143 
01144 int
01145 ldap_pvt_thread_rdwr_active( ldap_pvt_thread_rdwr_t *rwlock )
01146 {
01147        check_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_active" );
01148        return ldap_int_thread_rdwr_active( WRAPPED( rwlock ) );
01149 }
01150 
01151 #endif /* LDAP_RDWR_DEBUG && !LDAP_THREAD_HAVE_RDWR */
01152 
01153 
01154 /* Some wrappers for LDAP_THREAD_POOL_IMPLEMENTATION: */
01155 #ifdef LDAP_THREAD_POOL_IMPLEMENTATION
01156 
01157 int
01158 ldap_pvt_thread_pool_init(
01159        ldap_pvt_thread_pool_t *tpool,
01160        int max_threads,
01161        int max_pending )
01162 {
01163        int rc;
01164        if( !options_done )
01165               get_options();
01166        ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_init" );
01167        rc = ldap_int_thread_pool_init( tpool, max_threads, max_pending );
01168        if( rc ) {
01169               ERROR( rc, "ldap_pvt_thread_pool_init" );
01170        } else {
01171               adjust_count( Idx_tpool, +1 );
01172        }
01173        return rc;
01174 }
01175 
01176 int
01177 ldap_pvt_thread_pool_submit(
01178        ldap_pvt_thread_pool_t *tpool,
01179        ldap_pvt_thread_start_t *start_routine, void *arg )
01180 {
01181        int rc, has_pool;
01182        ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_submit" );
01183        has_pool = (tpool && *tpool);
01184        rc = ldap_int_thread_pool_submit( tpool, start_routine, arg );
01185        if( has_pool )
01186               ERROR_IF( rc, "ldap_pvt_thread_pool_submit" );
01187        return rc;
01188 }
01189 
01190 int
01191 ldap_pvt_thread_pool_maxthreads(
01192        ldap_pvt_thread_pool_t *tpool,
01193        int max_threads )
01194 {
01195        ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_maxthreads" );
01196        return ldap_int_thread_pool_maxthreads(   tpool, max_threads );
01197 }
01198 
01199 int
01200 ldap_pvt_thread_pool_backload( ldap_pvt_thread_pool_t *tpool )
01201 {
01202        ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_backload" );
01203        return ldap_int_thread_pool_backload( tpool );
01204 }
01205 
01206 int
01207 ldap_pvt_thread_pool_destroy( ldap_pvt_thread_pool_t *tpool, int run_pending )
01208 {
01209        int rc, has_pool;
01210        ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_destroy" );
01211        has_pool = (tpool && *tpool);
01212        rc = ldap_int_thread_pool_destroy( tpool, run_pending );
01213        if( has_pool ) {
01214               if( rc ) {
01215                      ERROR( rc, "ldap_pvt_thread_pool_destroy" );
01216               } else {
01217                      adjust_count( Idx_tpool, -1 );
01218               }
01219        }
01220        return rc;
01221 }
01222 
01223 int
01224 ldap_pvt_thread_pool_pause( ldap_pvt_thread_pool_t *tpool )
01225 {
01226        ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_pause" );
01227        return ldap_int_thread_pool_pause( tpool );
01228 }
01229 
01230 int
01231 ldap_pvt_thread_pool_resume( ldap_pvt_thread_pool_t *tpool )
01232 {
01233        ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_resume" );
01234        return ldap_int_thread_pool_resume( tpool );
01235 }
01236 
01237 int
01238 ldap_pvt_thread_pool_getkey(
01239        void *xctx,
01240        void *key,
01241        void **data,
01242        ldap_pvt_thread_pool_keyfree_t **kfree )
01243 {
01244 #if 0 /* Function is used by ch_free() via slap_sl_contxt() in slapd */
01245        ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_getkey" );
01246 #endif
01247        return ldap_int_thread_pool_getkey( xctx, key, data, kfree );
01248 }
01249 
01250 int
01251 ldap_pvt_thread_pool_setkey(
01252        void *xctx,
01253        void *key,
01254        void *data,
01255        ldap_pvt_thread_pool_keyfree_t *kfree,
01256        void **olddatap,
01257        ldap_pvt_thread_pool_keyfree_t **oldkfreep )
01258 {
01259        int rc;
01260        ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_setkey" );
01261        rc = ldap_int_thread_pool_setkey(
01262               xctx, key, data, kfree, olddatap, oldkfreep );
01263        ERROR_IF( rc, "ldap_pvt_thread_pool_setkey" );
01264        return rc;
01265 }
01266 
01267 void
01268 ldap_pvt_thread_pool_purgekey( void *key )
01269 {
01270        ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_purgekey" );
01271        ldap_int_thread_pool_purgekey( key );
01272 }
01273 
01274 void *
01275 ldap_pvt_thread_pool_context( void )
01276 {
01277 #if 0 /* Function is used by ch_free() via slap_sl_contxt() in slapd */
01278        ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_context" );
01279 #endif
01280        return ldap_int_thread_pool_context();
01281 }
01282 
01283 void
01284 ldap_pvt_thread_pool_context_reset( void *vctx )
01285 {
01286        ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_context_reset" );
01287        ldap_int_thread_pool_context_reset( vctx );
01288 }
01289 
01290 #endif /* LDAP_THREAD_POOL_IMPLEMENTATION */
01291 
01292 #endif /* LDAP_THREAD_DEBUG */