1*cf1d77f7Schristos /* $NetBSD: thr_debug.c,v 1.2 2021/08/14 16:14:56 christos Exp $ */
292cfeba6Schristos
392cfeba6Schristos /* thr_debug.c - wrapper around the chosen thread wrapper, for debugging. */
492cfeba6Schristos /* $OpenLDAP$ */
592cfeba6Schristos /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
692cfeba6Schristos *
792cfeba6Schristos * Copyright 2005-2021 The OpenLDAP Foundation.
892cfeba6Schristos * All rights reserved.
992cfeba6Schristos *
1092cfeba6Schristos * Redistribution and use in source and binary forms, with or without
1192cfeba6Schristos * modification, are permitted only as authorized by the OpenLDAP
1292cfeba6Schristos * Public License.
1392cfeba6Schristos *
1492cfeba6Schristos * A copy of this license is available in file LICENSE in the
1592cfeba6Schristos * top-level directory of the distribution or, alternatively, at
1692cfeba6Schristos * <http://www.OpenLDAP.org/license.html>.
1792cfeba6Schristos */
1892cfeba6Schristos
1992cfeba6Schristos /*
2092cfeba6Schristos * This package provides several types of thread operation debugging:
2192cfeba6Schristos *
2292cfeba6Schristos * - Check the results of operations on threads, mutexes, condition
2392cfeba6Schristos * variables and read/write locks. Also check some thread pool
2492cfeba6Schristos * operations, but not those for which failure can happen in normal
2592cfeba6Schristos * slapd operation.
2692cfeba6Schristos *
2792cfeba6Schristos * - Wrap those types except threads and pools in structs with state
2892cfeba6Schristos * information, and check that on all operations:
2992cfeba6Schristos *
3092cfeba6Schristos * + Check that the resources are initialized and are only used at
3192cfeba6Schristos * their original address (i.e. not realloced or copied).
3292cfeba6Schristos *
3392cfeba6Schristos * + Check the owner (thread ID) on mutex operations.
3492cfeba6Schristos *
3592cfeba6Schristos * + Optionally allocate a reference to a byte of dummy memory.
3692cfeba6Schristos * This lets malloc debuggers see some incorrect use as memory
3792cfeba6Schristos * leaks, access to freed memory, etc.
3892cfeba6Schristos *
3992cfeba6Schristos * - Print an error message and by default abort() upon errors.
4092cfeba6Schristos *
4192cfeba6Schristos * - Print a count of leaked thread resources after cleanup.
4292cfeba6Schristos *
4392cfeba6Schristos * Compile-time (./configure) setup: Macros defined in CPPFLAGS.
4492cfeba6Schristos *
4592cfeba6Schristos * LDAP_THREAD_DEBUG or LDAP_THREAD_DEBUG=2
4692cfeba6Schristos * Enables debugging, but value & 2 turns off type wrapping.
4792cfeba6Schristos *
4892cfeba6Schristos * LDAP_UINTPTR_T=integer type to hold pointers, preferably unsigned.
4992cfeba6Schristos * Used by dummy memory option "scramble". Default = unsigned long.
5092cfeba6Schristos *
5192cfeba6Schristos * LDAP_DEBUG_THREAD_NONE = initializer for a "no thread" thread ID.
5292cfeba6Schristos *
5392cfeba6Schristos * In addition, you may need to set up an implementation-specific way
5492cfeba6Schristos * to enable whatever error checking your thread library provides.
5592cfeba6Schristos * Currently only implemented for Posix threads (pthreads), where
5692cfeba6Schristos * you may need to define LDAP_INT_THREAD_MUTEXATTR. The default
5792cfeba6Schristos * is PTHREAD_MUTEX_ERRORCHECK, or PTHREAD_MUTEX_ERRORCHECK_NP for
5892cfeba6Schristos * Linux threads. See pthread_mutexattr_settype(3).
5992cfeba6Schristos *
6092cfeba6Schristos * Run-time configuration:
6192cfeba6Schristos *
6292cfeba6Schristos * Memory debugging tools:
6392cfeba6Schristos * Tools that report uninitialized memory accesses should disable
6492cfeba6Schristos * such warnings about the function debug_already_initialized().
6592cfeba6Schristos * Alternatively, include "noreinit" (below) in $LDAP_THREAD_DEBUG.
6692cfeba6Schristos *
6792cfeba6Schristos * Environment variable $LDAP_THREAD_DEBUG:
6892cfeba6Schristos * The variable may contain a comma- or space-separated option list.
6992cfeba6Schristos * Options:
7092cfeba6Schristos * off - Disable this package. (It still slows things down).
7192cfeba6Schristos * tracethreads - Report create/join/exit/kill of threads.
7292cfeba6Schristos * noabort - Do not abort() on errors.
7392cfeba6Schristos * noerror - Do not report errors. Implies noabort.
7492cfeba6Schristos * nocount - Do not report counts of unreleased resources.
7592cfeba6Schristos * nosync - Disable tests that use synchronization and thus
7692cfeba6Schristos * clearly affect thread scheduling:
7792cfeba6Schristos * Implies nocount, and cancels threadID if that is set.
7892cfeba6Schristos * Note that if you turn on tracethreads or malloc
7992cfeba6Schristos * debugging, these also use library calls which may
8092cfeba6Schristos * affect thread scheduling (fprintf and malloc).
8192cfeba6Schristos * The following options do not apply if type wrapping is disabled:
8292cfeba6Schristos * nomem - Do not check memory operations.
8392cfeba6Schristos * Implies noreinit,noalloc.
8492cfeba6Schristos * noreinit - Do not catch reinitialization of existing resources.
8592cfeba6Schristos * (That test accesses uninitialized memory).
8692cfeba6Schristos * threadID - Trace thread IDs. Currently mostly useless.
8792cfeba6Schristos * Malloc debugging -- allocate dummy memory for initialized
8892cfeba6Schristos * resources, so malloc debuggers will report them as memory leaks:
8992cfeba6Schristos * noalloc - Default. Do not allocate dummy memory.
9092cfeba6Schristos * alloc - Store a pointer to dummy memory. However, leak
9192cfeba6Schristos * detectors might not catch unreleased resources in
9292cfeba6Schristos * global variables.
9392cfeba6Schristos * scramble - Store bitwise complement of dummy memory pointer.
9492cfeba6Schristos * That never escapes memory leak detectors -
9592cfeba6Schristos * but detection while the program is running will
9692cfeba6Schristos * report active resources as leaks. Do not
9792cfeba6Schristos * use this if a garbage collector is in use:-)
9892cfeba6Schristos * adjptr - Point to end of dummy memory.
9992cfeba6Schristos * Purify reports these as "potential leaks" (PLK).
10092cfeba6Schristos * I have not checked other malloc debuggers.
10192cfeba6Schristos */
10292cfeba6Schristos
10392cfeba6Schristos #include <sys/cdefs.h>
104*cf1d77f7Schristos __RCSID("$NetBSD: thr_debug.c,v 1.2 2021/08/14 16:14:56 christos Exp $");
10592cfeba6Schristos
10692cfeba6Schristos #include "portable.h"
10792cfeba6Schristos
10892cfeba6Schristos #if defined( LDAP_THREAD_DEBUG )
10992cfeba6Schristos
11092cfeba6Schristos #include <stdio.h>
11192cfeba6Schristos #include <ac/errno.h>
11292cfeba6Schristos #include <ac/stdlib.h>
11392cfeba6Schristos #include <ac/string.h>
11492cfeba6Schristos
11592cfeba6Schristos #include "ldap_pvt_thread.h" /* Get the thread interface */
11692cfeba6Schristos #define LDAP_THREAD_IMPLEMENTATION
11792cfeba6Schristos #define LDAP_THREAD_DEBUG_IMPLEMENTATION
11892cfeba6Schristos #define LDAP_THREAD_RDWR_IMPLEMENTATION
11992cfeba6Schristos #define LDAP_THREAD_POOL_IMPLEMENTATION
12092cfeba6Schristos #include "ldap_thr_debug.h" /* Get the underlying implementation */
12192cfeba6Schristos
12292cfeba6Schristos #ifndef LDAP_THREAD_DEBUG_WRAP
12392cfeba6Schristos #undef LDAP_THREAD_DEBUG_THREAD_ID
12492cfeba6Schristos #elif !defined LDAP_THREAD_DEBUG_THREAD_ID
12592cfeba6Schristos #define LDAP_THREAD_DEBUG_THREAD_ID 1
12692cfeba6Schristos #endif
12792cfeba6Schristos
12892cfeba6Schristos /* Use native malloc - the OpenLDAP wrappers may defeat malloc debuggers */
12992cfeba6Schristos #undef malloc
13092cfeba6Schristos #undef calloc
13192cfeba6Schristos #undef realloc
13292cfeba6Schristos #undef free
13392cfeba6Schristos
13492cfeba6Schristos
13592cfeba6Schristos /* Options from environment variable $LDAP_THREAD_DEBUG */
13692cfeba6Schristos enum { Count_no = 0, Count_yes, Count_reported, Count_reported_more };
13792cfeba6Schristos static int count = Count_yes;
13892cfeba6Schristos #ifdef LDAP_THREAD_DEBUG_WRAP
13992cfeba6Schristos enum { Wrap_noalloc, Wrap_alloc, Wrap_scramble, Wrap_adjptr };
14092cfeba6Schristos static int wraptype = Wrap_noalloc, wrap_offset, unwrap_offset;
14192cfeba6Schristos static int nomem, noreinit;
14292cfeba6Schristos #endif
14392cfeba6Schristos #if LDAP_THREAD_DEBUG_THREAD_ID +0
14492cfeba6Schristos static int threadID;
14592cfeba6Schristos #else
14692cfeba6Schristos enum { threadID = 0 };
14792cfeba6Schristos #endif
14892cfeba6Schristos static int nodebug, noabort, noerror, nosync, tracethreads;
14992cfeba6Schristos static int wrap_threads;
15092cfeba6Schristos static int options_done;
15192cfeba6Schristos
15292cfeba6Schristos
15392cfeba6Schristos /* ldap_pvt_thread_initialize() called, ldap_pvt_thread_destroy() not called */
15492cfeba6Schristos static int threading_enabled;
15592cfeba6Schristos
15692cfeba6Schristos
15792cfeba6Schristos /* Resource counts */
15892cfeba6Schristos enum {
15992cfeba6Schristos Idx_unexited_thread, Idx_unjoined_thread, Idx_locked_mutex,
16092cfeba6Schristos Idx_mutex, Idx_cond, Idx_rdwr, Idx_tpool, Idx_max
16192cfeba6Schristos };
16292cfeba6Schristos static int resource_counts[Idx_max];
16392cfeba6Schristos static const char *const resource_names[] = {
16492cfeba6Schristos "unexited threads", "unjoined threads", "locked mutexes",
16592cfeba6Schristos "mutexes", "conds", "rdwrs", "thread pools"
16692cfeba6Schristos };
16792cfeba6Schristos static ldap_int_thread_mutex_t resource_mutexes[Idx_max];
16892cfeba6Schristos
16992cfeba6Schristos
17092cfeba6Schristos /* Hide pointers from malloc debuggers. */
17192cfeba6Schristos #define SCRAMBLE(ptr) (~(LDAP_UINTPTR_T) (ptr))
17292cfeba6Schristos #define UNSCRAMBLE_usagep(num) ((ldap_debug_usage_info_t *) ~(num))
17392cfeba6Schristos #define UNSCRAMBLE_dummyp(num) ((unsigned char *) ~(num))
17492cfeba6Schristos
17592cfeba6Schristos
17692cfeba6Schristos #define WARN(var, msg) (warn (__FILE__, __LINE__, (msg), #var, (var)))
17792cfeba6Schristos #define WARN_IF(rc, msg) {if (rc) warn (__FILE__, __LINE__, (msg), #rc, (rc));}
17892cfeba6Schristos
17992cfeba6Schristos #define ERROR(var, msg) { \
18092cfeba6Schristos if (!noerror) { \
18192cfeba6Schristos errmsg(__FILE__, __LINE__, (msg), #var, (var)); \
18292cfeba6Schristos if( !noabort ) abort(); \
18392cfeba6Schristos } \
18492cfeba6Schristos }
18592cfeba6Schristos
18692cfeba6Schristos #define ERROR_IF(rc, msg) { \
18792cfeba6Schristos if (!noerror) { \
18892cfeba6Schristos int rc_ = (rc); \
18992cfeba6Schristos if (rc_) { \
19092cfeba6Schristos errmsg(__FILE__, __LINE__, (msg), #rc, rc_); \
19192cfeba6Schristos if( !noabort ) abort(); \
19292cfeba6Schristos } \
19392cfeba6Schristos } \
19492cfeba6Schristos }
19592cfeba6Schristos
19692cfeba6Schristos #ifdef LDAP_THREAD_DEBUG_WRAP
19792cfeba6Schristos #define MEMERROR_IF(rc, msg, mem_act) { \
19892cfeba6Schristos if (!noerror) { \
19992cfeba6Schristos int rc_ = (rc); \
20092cfeba6Schristos if (rc_) { \
20192cfeba6Schristos errmsg(__FILE__, __LINE__, (msg), #rc, rc_); \
20292cfeba6Schristos if( wraptype != Wrap_noalloc ) { mem_act; } \
20392cfeba6Schristos if( !noabort ) abort(); \
20492cfeba6Schristos } \
20592cfeba6Schristos } \
20692cfeba6Schristos }
20792cfeba6Schristos #endif /* LDAP_THREAD_DEBUG_WRAP */
20892cfeba6Schristos
20992cfeba6Schristos #if 0
21092cfeba6Schristos static void
21192cfeba6Schristos warn( const char *file, int line, const char *msg, const char *var, int val )
21292cfeba6Schristos {
21392cfeba6Schristos fprintf( stderr,
21492cfeba6Schristos (strpbrk( var, "!=" )
21592cfeba6Schristos ? "%s:%d: %s warning: %s\n"
21692cfeba6Schristos : "%s:%d: %s warning: %s is %d\n"),
21792cfeba6Schristos file, line, msg, var, val );
21892cfeba6Schristos }
21992cfeba6Schristos #endif
22092cfeba6Schristos
22192cfeba6Schristos static void
errmsg(const char * file,int line,const char * msg,const char * var,int val)22292cfeba6Schristos errmsg( const char *file, int line, const char *msg, const char *var, int val )
22392cfeba6Schristos {
22492cfeba6Schristos fprintf( stderr,
22592cfeba6Schristos (strpbrk( var, "!=" )
22692cfeba6Schristos ? "%s:%d: %s error: %s\n"
22792cfeba6Schristos : "%s:%d: %s error: %s is %d\n"),
22892cfeba6Schristos file, line, msg, var, val );
22992cfeba6Schristos }
23092cfeba6Schristos
23192cfeba6Schristos static void
count_resource_leaks(void)23292cfeba6Schristos count_resource_leaks( void )
23392cfeba6Schristos {
23492cfeba6Schristos int i, j;
23592cfeba6Schristos char errbuf[200];
23692cfeba6Schristos if( count == Count_yes ) {
23792cfeba6Schristos count = Count_reported;
23892cfeba6Schristos #if 0 /* Could break if there are still threads after atexit */
23992cfeba6Schristos for( i = j = 0; i < Idx_max; i++ )
24092cfeba6Schristos j |= ldap_int_thread_mutex_destroy( &resource_mutexes[i] );
24192cfeba6Schristos WARN_IF( j, "ldap_debug_thread_destroy:mutexes" );
24292cfeba6Schristos #endif
24392cfeba6Schristos for( i = j = 0; i < Idx_max; i++ )
24492cfeba6Schristos if( resource_counts[i] )
24592cfeba6Schristos j += sprintf( errbuf + j, ", %d %s",
24692cfeba6Schristos resource_counts[i], resource_names[i] );
24792cfeba6Schristos if( j )
24892cfeba6Schristos fprintf( stderr, "== thr_debug: Leaked%s. ==\n", errbuf + 1 );
24992cfeba6Schristos }
25092cfeba6Schristos }
25192cfeba6Schristos
25292cfeba6Schristos static void
get_options(void)25392cfeba6Schristos get_options( void )
25492cfeba6Schristos {
25592cfeba6Schristos static const struct option_info_s {
25692cfeba6Schristos const char *name;
25792cfeba6Schristos int *var, val;
25892cfeba6Schristos } option_info[] = {
25992cfeba6Schristos { "off", &nodebug, 1 },
26092cfeba6Schristos { "noabort", &noabort, 1 },
26192cfeba6Schristos { "noerror", &noerror, 1 },
26292cfeba6Schristos { "nocount", &count, Count_no },
26392cfeba6Schristos { "nosync", &nosync, 1 },
26492cfeba6Schristos #if LDAP_THREAD_DEBUG_THREAD_ID +0
26592cfeba6Schristos { "threadID", &threadID, 1 },
26692cfeba6Schristos #endif
26792cfeba6Schristos #ifdef LDAP_THREAD_DEBUG_WRAP
26892cfeba6Schristos { "nomem", &nomem, 1 },
26992cfeba6Schristos { "noreinit", &noreinit, 1 },
27092cfeba6Schristos { "noalloc", &wraptype, Wrap_noalloc },
27192cfeba6Schristos { "alloc", &wraptype, Wrap_alloc },
27292cfeba6Schristos { "adjptr", &wraptype, Wrap_adjptr },
27392cfeba6Schristos { "scramble", &wraptype, Wrap_scramble },
27492cfeba6Schristos #endif
27592cfeba6Schristos { "tracethreads", &tracethreads, 1 },
27692cfeba6Schristos { NULL, NULL, 0 }
27792cfeba6Schristos };
27892cfeba6Schristos const char *s = getenv( "LDAP_THREAD_DEBUG" );
27992cfeba6Schristos if( s != NULL ) {
28092cfeba6Schristos while( *(s += strspn( s, ", \t\r\n" )) != '\0' ) {
28192cfeba6Schristos size_t optlen = strcspn( s, ", \t\r\n" );
28292cfeba6Schristos const struct option_info_s *oi = option_info;
28392cfeba6Schristos while( oi->name &&
28492cfeba6Schristos (strncasecmp( oi->name, s, optlen ) || oi->name[optlen]) )
28592cfeba6Schristos oi++;
28692cfeba6Schristos if( oi->name )
28792cfeba6Schristos *oi->var = oi->val;
28892cfeba6Schristos else
28992cfeba6Schristos fprintf( stderr,
29092cfeba6Schristos "== thr_debug: Unknown $%s option '%.*s' ==\n",
29192cfeba6Schristos "LDAP_THREAD_DEBUG", (int) optlen, s );
29292cfeba6Schristos s += optlen;
29392cfeba6Schristos }
29492cfeba6Schristos }
29592cfeba6Schristos if( nodebug ) {
29692cfeba6Schristos tracethreads = 0;
29792cfeba6Schristos nosync = noerror = 1;
29892cfeba6Schristos }
29992cfeba6Schristos if( nosync )
30092cfeba6Schristos count = Count_no;
30192cfeba6Schristos if( noerror )
30292cfeba6Schristos noabort = 1;
30392cfeba6Schristos #if LDAP_THREAD_DEBUG_THREAD_ID +0
30492cfeba6Schristos if( nosync )
30592cfeba6Schristos threadID = 0;
30692cfeba6Schristos #endif
30792cfeba6Schristos #ifdef LDAP_THREAD_DEBUG_WRAP
30892cfeba6Schristos if( noerror )
30992cfeba6Schristos nomem = 1;
31092cfeba6Schristos if( !nomem ) {
31192cfeba6Schristos static const ldap_debug_usage_info_t usage;
31292cfeba6Schristos if( sizeof(LDAP_UINTPTR_T) < sizeof(unsigned char *)
31392cfeba6Schristos || sizeof(LDAP_UINTPTR_T) < sizeof(ldap_debug_usage_info_t *)
31492cfeba6Schristos || UNSCRAMBLE_usagep( SCRAMBLE( &usage ) ) != &usage
31592cfeba6Schristos || UNSCRAMBLE_dummyp( SCRAMBLE( (unsigned char *) 0 ) ) )
31692cfeba6Schristos {
31792cfeba6Schristos fputs( "== thr_debug: Memory checks unsupported, "
31892cfeba6Schristos "adding nomem to $LDAP_THREAD_DEBUG ==\n", stderr );
31992cfeba6Schristos nomem = 1;
32092cfeba6Schristos }
32192cfeba6Schristos }
32292cfeba6Schristos if( nomem ) {
32392cfeba6Schristos noreinit = 1;
32492cfeba6Schristos wraptype = Wrap_noalloc;
32592cfeba6Schristos }
32692cfeba6Schristos unwrap_offset = -(wrap_offset = (wraptype == Wrap_adjptr));
32792cfeba6Schristos #endif
32892cfeba6Schristos wrap_threads = (tracethreads || threadID || count);
32992cfeba6Schristos options_done = 1;
33092cfeba6Schristos }
33192cfeba6Schristos
33292cfeba6Schristos
33392cfeba6Schristos #ifndef LDAP_THREAD_DEBUG_WRAP
33492cfeba6Schristos
33592cfeba6Schristos #define WRAPPED(ptr) (ptr)
33692cfeba6Schristos #define GET_OWNER(ptr) 0
33792cfeba6Schristos #define SET_OWNER(ptr, thread) ((void) 0)
33892cfeba6Schristos #define RESET_OWNER(ptr) ((void) 0)
33992cfeba6Schristos #define ASSERT_OWNER(ptr, msg) ((void) 0)
34092cfeba6Schristos #define ASSERT_NO_OWNER(ptr, msg) ((void) 0)
34192cfeba6Schristos
34292cfeba6Schristos #define init_usage(ptr, msg) ((void) 0)
34392cfeba6Schristos #define check_usage(ptr, msg) ((void) 0)
34492cfeba6Schristos #define destroy_usage(ptr) ((void) 0)
34592cfeba6Schristos
34692cfeba6Schristos #else /* LDAP_THREAD_DEBUG_WRAP */
34792cfeba6Schristos
34892cfeba6Schristos /* Specialize this if the initializer is not appropriate. */
34992cfeba6Schristos /* The ASSERT_NO_OWNER() definition may also need an override. */
35092cfeba6Schristos #ifndef LDAP_DEBUG_THREAD_NONE
35192cfeba6Schristos #define LDAP_DEBUG_THREAD_NONE { -1 } /* "no thread" ldap_int_thread_t value */
35292cfeba6Schristos #endif
35392cfeba6Schristos
35492cfeba6Schristos static const ldap_int_thread_t ldap_debug_thread_none = LDAP_DEBUG_THREAD_NONE;
35592cfeba6Schristos
35692cfeba6Schristos #define THREAD_MUTEX_OWNER(mutex) \
35792cfeba6Schristos ldap_int_thread_equal( (mutex)->owner, ldap_int_thread_self() )
35892cfeba6Schristos
35992cfeba6Schristos void
ldap_debug_thread_assert_mutex_owner(const char * file,int line,const char * msg,ldap_pvt_thread_mutex_t * mutex)36092cfeba6Schristos ldap_debug_thread_assert_mutex_owner(
36192cfeba6Schristos const char *file,
36292cfeba6Schristos int line,
36392cfeba6Schristos const char *msg,
36492cfeba6Schristos ldap_pvt_thread_mutex_t *mutex )
36592cfeba6Schristos {
36692cfeba6Schristos if( !(noerror || THREAD_MUTEX_OWNER( mutex )) ) {
36792cfeba6Schristos errmsg( file, line, msg, "ASSERT_MUTEX_OWNER", 0 );
36892cfeba6Schristos if( !noabort ) abort();
36992cfeba6Schristos }
37092cfeba6Schristos }
37192cfeba6Schristos
37292cfeba6Schristos #define WRAPPED(ptr) (&(ptr)->wrapped)
37392cfeba6Schristos #define GET_OWNER(ptr) ((ptr)->owner)
37492cfeba6Schristos #define SET_OWNER(ptr, thread) ((ptr)->owner = (thread))
37592cfeba6Schristos #define RESET_OWNER(ptr) ((ptr)->owner = ldap_debug_thread_none)
37692cfeba6Schristos #define ASSERT_OWNER(ptr, msg) ERROR_IF( !THREAD_MUTEX_OWNER( ptr ), msg )
37792cfeba6Schristos #ifndef ASSERT_NO_OWNER
37892cfeba6Schristos #define ASSERT_NO_OWNER(ptr, msg) ERROR_IF( \
37992cfeba6Schristos !ldap_int_thread_equal( (ptr)->owner, ldap_debug_thread_none ), msg )
38092cfeba6Schristos #endif
38192cfeba6Schristos
38292cfeba6Schristos /* Try to provoke memory access error (for malloc debuggers) */
38392cfeba6Schristos #define PEEK(mem) {if (-*(volatile const unsigned char *)(mem)) debug_noop();}
38492cfeba6Schristos
38592cfeba6Schristos static void debug_noop( void );
38692cfeba6Schristos static int debug_already_initialized( const ldap_debug_usage_info_t *usage );
38792cfeba6Schristos
38892cfeba6Schristos /* Name used for clearer error message */
38992cfeba6Schristos #define IS_COPY_OR_MOVED(usage) ((usage)->self != SCRAMBLE( usage ))
39092cfeba6Schristos
39192cfeba6Schristos #define DUMMY_ADDR(usage) \
39292cfeba6Schristos (wraptype == Wrap_scramble \
39392cfeba6Schristos ? UNSCRAMBLE_dummyp( (usage)->mem.num ) \
39492cfeba6Schristos : (usage)->mem.ptr + unwrap_offset)
39592cfeba6Schristos
39692cfeba6Schristos /* Mark resource as initialized */
39792cfeba6Schristos static void
init_usage(ldap_debug_usage_info_t * usage,const char * msg)39892cfeba6Schristos init_usage( ldap_debug_usage_info_t *usage, const char *msg )
39992cfeba6Schristos {
40092cfeba6Schristos if( !options_done )
40192cfeba6Schristos get_options();
40292cfeba6Schristos if( !nomem ) {
40392cfeba6Schristos if( !noreinit ) {
40492cfeba6Schristos MEMERROR_IF( debug_already_initialized( usage ), msg, {
40592cfeba6Schristos /* Provoke malloc debuggers */
40692cfeba6Schristos unsigned char *dummy = DUMMY_ADDR( usage );
40792cfeba6Schristos PEEK( dummy );
40892cfeba6Schristos free( dummy );
40992cfeba6Schristos free( dummy );
41092cfeba6Schristos } );
41192cfeba6Schristos }
41292cfeba6Schristos if( wraptype != Wrap_noalloc ) {
41392cfeba6Schristos unsigned char *dummy = malloc( 1 );
41492cfeba6Schristos assert( dummy != NULL );
41592cfeba6Schristos if( wraptype == Wrap_scramble ) {
41692cfeba6Schristos usage->mem.num = SCRAMBLE( dummy );
41792cfeba6Schristos /* Verify that ptr<->integer casts work on this host */
41892cfeba6Schristos assert( UNSCRAMBLE_dummyp( usage->mem.num ) == dummy );
41992cfeba6Schristos } else {
42092cfeba6Schristos usage->mem.ptr = dummy + wrap_offset;
42192cfeba6Schristos }
42292cfeba6Schristos }
42392cfeba6Schristos } else {
42492cfeba6Schristos /* Unused, but set for readability in debugger */
42592cfeba6Schristos usage->mem.ptr = NULL;
42692cfeba6Schristos }
42792cfeba6Schristos usage->self = SCRAMBLE( usage ); /* If nomem, only for debugger */
42892cfeba6Schristos usage->magic = ldap_debug_magic;
42992cfeba6Schristos usage->state = ldap_debug_state_inited;
43092cfeba6Schristos }
43192cfeba6Schristos
43292cfeba6Schristos /* Check that resource is initialized and not copied/realloced */
43392cfeba6Schristos static void
check_usage(const ldap_debug_usage_info_t * usage,const char * msg)43492cfeba6Schristos check_usage( const ldap_debug_usage_info_t *usage, const char *msg )
43592cfeba6Schristos {
43692cfeba6Schristos enum { Is_destroyed = 1 }; /* Name used for clearer error message */
43792cfeba6Schristos
43892cfeba6Schristos if( usage->magic != ldap_debug_magic ) {
43992cfeba6Schristos ERROR( usage->magic, msg );
44092cfeba6Schristos return;
44192cfeba6Schristos }
44292cfeba6Schristos switch( usage->state ) {
44392cfeba6Schristos case ldap_debug_state_destroyed:
44492cfeba6Schristos MEMERROR_IF( Is_destroyed, msg, {
44592cfeba6Schristos PEEK( DUMMY_ADDR( usage ) );
44692cfeba6Schristos } );
44792cfeba6Schristos break;
44892cfeba6Schristos default:
44992cfeba6Schristos ERROR( usage->state, msg );
45092cfeba6Schristos break;
45192cfeba6Schristos case ldap_debug_state_inited:
45292cfeba6Schristos if( !nomem ) {
45392cfeba6Schristos MEMERROR_IF( IS_COPY_OR_MOVED( usage ), msg, {
45492cfeba6Schristos PEEK( DUMMY_ADDR( usage ) );
45592cfeba6Schristos PEEK( UNSCRAMBLE_usagep( usage->self ) );
45692cfeba6Schristos } );
45792cfeba6Schristos }
45892cfeba6Schristos break;
45992cfeba6Schristos }
46092cfeba6Schristos }
46192cfeba6Schristos
46292cfeba6Schristos /* Mark resource as destroyed. */
46392cfeba6Schristos /* Does not check for errors, call check_usage()/init_usage() first. */
46492cfeba6Schristos static void
destroy_usage(ldap_debug_usage_info_t * usage)46592cfeba6Schristos destroy_usage( ldap_debug_usage_info_t *usage )
46692cfeba6Schristos {
46792cfeba6Schristos if( usage->state == ldap_debug_state_inited ) {
46892cfeba6Schristos if( wraptype != Wrap_noalloc ) {
46992cfeba6Schristos free( DUMMY_ADDR( usage ) );
47092cfeba6Schristos /* Do not reset the DUMMY_ADDR, leave it for malloc debuggers
47192cfeba6Schristos * in case the resource is used after it is freed. */
47292cfeba6Schristos }
47392cfeba6Schristos usage->state = ldap_debug_state_destroyed;
47492cfeba6Schristos }
47592cfeba6Schristos }
47692cfeba6Schristos
47792cfeba6Schristos /* Define these after they are used, so they are hopefully not inlined */
47892cfeba6Schristos
47992cfeba6Schristos static void
debug_noop(void)48092cfeba6Schristos debug_noop( void )
48192cfeba6Schristos {
48292cfeba6Schristos }
48392cfeba6Schristos
48492cfeba6Schristos /*
48592cfeba6Schristos * Valid programs access uninitialized memory here unless "noreinit".
48692cfeba6Schristos *
48792cfeba6Schristos * Returns true if the resource is initialized and not copied/realloced.
48892cfeba6Schristos */
48992cfeba6Schristos LDAP_GCCATTR((noinline))
49092cfeba6Schristos static int
debug_already_initialized(const ldap_debug_usage_info_t * usage)49192cfeba6Schristos debug_already_initialized( const ldap_debug_usage_info_t *usage )
49292cfeba6Schristos {
49392cfeba6Schristos /*
49492cfeba6Schristos * 'ret' keeps the Valgrind warning "Conditional jump or move
49592cfeba6Schristos * depends on uninitialised value(s)" _inside_ this function.
49692cfeba6Schristos */
49792cfeba6Schristos volatile int ret = 0;
49892cfeba6Schristos if( usage->state == ldap_debug_state_inited )
49992cfeba6Schristos if( !IS_COPY_OR_MOVED( usage ) )
50092cfeba6Schristos if( usage->magic == ldap_debug_magic )
50192cfeba6Schristos ret = 1;
50292cfeba6Schristos return ret;
50392cfeba6Schristos }
50492cfeba6Schristos
50592cfeba6Schristos #endif /* LDAP_THREAD_DEBUG_WRAP */
50692cfeba6Schristos
50792cfeba6Schristos
50892cfeba6Schristos #if !(LDAP_THREAD_DEBUG_THREAD_ID +0)
50992cfeba6Schristos
51092cfeba6Schristos typedef void ldap_debug_thread_t;
51192cfeba6Schristos #define init_thread_info() {}
51292cfeba6Schristos #define with_thread_info_lock(statements) { statements; }
51392cfeba6Schristos #define thread_info_detached(t) 0
51492cfeba6Schristos #define add_thread_info(msg, thr, det) ((void) 0)
51592cfeba6Schristos #define remove_thread_info(tinfo, msg) ((void) 0)
51692cfeba6Schristos #define get_thread_info(thread, msg) NULL
51792cfeba6Schristos
51892cfeba6Schristos #else /* LDAP_THREAD_DEBUG_THREAD_ID */
51992cfeba6Schristos
52092cfeba6Schristos /*
52192cfeba6Schristos * Thread ID tracking. Currently achieves little.
52292cfeba6Schristos * Should be either expanded or deleted.
52392cfeba6Schristos */
52492cfeba6Schristos
52592cfeba6Schristos /*
52692cfeba6Schristos * Array of threads. Used instead of making ldap_pvt_thread_t a wrapper
52792cfeba6Schristos * around ldap_int_thread_t, which would slow down ldap_pvt_thread_self().
52892cfeba6Schristos */
52992cfeba6Schristos typedef struct {
53092cfeba6Schristos ldap_pvt_thread_t wrapped;
53192cfeba6Schristos ldap_debug_usage_info_t usage;
53292cfeba6Schristos int detached;
53392cfeba6Schristos int idx;
53492cfeba6Schristos } ldap_debug_thread_t;
53592cfeba6Schristos
53692cfeba6Schristos static ldap_debug_thread_t **thread_info;
53792cfeba6Schristos static unsigned int thread_info_size, thread_info_used;
53892cfeba6Schristos static ldap_int_thread_mutex_t thread_info_mutex;
53992cfeba6Schristos
54092cfeba6Schristos #define init_thread_info() { \
54192cfeba6Schristos if( threadID ) { \
54292cfeba6Schristos int mutex_init_rc = ldap_int_thread_mutex_init( &thread_info_mutex ); \
54392cfeba6Schristos assert( mutex_init_rc == 0 ); \
54492cfeba6Schristos } \
54592cfeba6Schristos }
54692cfeba6Schristos
54792cfeba6Schristos #define with_thread_info_lock(statements) { \
54892cfeba6Schristos int rc_wtl_ = ldap_int_thread_mutex_lock( &thread_info_mutex ); \
54992cfeba6Schristos assert( rc_wtl_ == 0 ); \
55092cfeba6Schristos { statements; } \
55192cfeba6Schristos rc_wtl_ = ldap_int_thread_mutex_unlock( &thread_info_mutex ); \
55292cfeba6Schristos assert( rc_wtl_ == 0 ); \
55392cfeba6Schristos }
55492cfeba6Schristos
55592cfeba6Schristos #define thread_info_detached(t) ((t)->detached)
55692cfeba6Schristos
55792cfeba6Schristos static void
add_thread_info(const char * msg,const ldap_pvt_thread_t * thread,int detached)55892cfeba6Schristos add_thread_info(
55992cfeba6Schristos const char *msg,
56092cfeba6Schristos const ldap_pvt_thread_t *thread,
56192cfeba6Schristos int detached )
56292cfeba6Schristos {
56392cfeba6Schristos ldap_debug_thread_t *t;
56492cfeba6Schristos
56592cfeba6Schristos if( thread_info_used >= thread_info_size ) {
56692cfeba6Schristos unsigned int more = thread_info_size + 8;
56792cfeba6Schristos unsigned int new_size = thread_info_size + more;
56892cfeba6Schristos
56992cfeba6Schristos t = calloc( more, sizeof(ldap_debug_thread_t) );
57092cfeba6Schristos assert( t != NULL );
57192cfeba6Schristos thread_info = realloc( thread_info, new_size * sizeof(*thread_info) );
57292cfeba6Schristos assert( thread_info != NULL );
57392cfeba6Schristos do {
57492cfeba6Schristos t->idx = thread_info_size;
57592cfeba6Schristos thread_info[thread_info_size++] = t++;
57692cfeba6Schristos } while( thread_info_size < new_size );
57792cfeba6Schristos }
57892cfeba6Schristos
57992cfeba6Schristos t = thread_info[thread_info_used];
58092cfeba6Schristos init_usage( &t->usage, msg );
58192cfeba6Schristos t->wrapped = *thread;
58292cfeba6Schristos t->detached = detached;
58392cfeba6Schristos thread_info_used++;
58492cfeba6Schristos }
58592cfeba6Schristos
58692cfeba6Schristos static void
remove_thread_info(ldap_debug_thread_t * t,const char * msg)58792cfeba6Schristos remove_thread_info( ldap_debug_thread_t *t, const char *msg )
58892cfeba6Schristos {
58992cfeba6Schristos ldap_debug_thread_t *last;
59092cfeba6Schristos int idx;
59192cfeba6Schristos check_usage( &t->usage, msg );
59292cfeba6Schristos destroy_usage( &t->usage );
59392cfeba6Schristos idx = t->idx;
59492cfeba6Schristos assert( thread_info[idx] == t );
59592cfeba6Schristos last = thread_info[--thread_info_used];
59692cfeba6Schristos assert( last->idx == thread_info_used );
59792cfeba6Schristos (thread_info[idx] = last)->idx = idx;
59892cfeba6Schristos (thread_info[thread_info_used] = t )->idx = thread_info_used;
59992cfeba6Schristos }
60092cfeba6Schristos
60192cfeba6Schristos static ldap_debug_thread_t *
get_thread_info(ldap_pvt_thread_t thread,const char * msg)60292cfeba6Schristos get_thread_info( ldap_pvt_thread_t thread, const char *msg )
60392cfeba6Schristos {
60492cfeba6Schristos unsigned int i;
60592cfeba6Schristos ldap_debug_thread_t *t;
60692cfeba6Schristos for( i = 0; i < thread_info_used; i++ ) {
60792cfeba6Schristos if( ldap_pvt_thread_equal( thread, thread_info[i]->wrapped ) )
60892cfeba6Schristos break;
60992cfeba6Schristos }
61092cfeba6Schristos ERROR_IF( i == thread_info_used, msg );
61192cfeba6Schristos t = thread_info[i];
61292cfeba6Schristos check_usage( &t->usage, msg );
61392cfeba6Schristos return t;
61492cfeba6Schristos }
61592cfeba6Schristos
61692cfeba6Schristos #endif /* LDAP_THREAD_DEBUG_THREAD_ID */
61792cfeba6Schristos
61892cfeba6Schristos
61992cfeba6Schristos static char *
thread_name(char * buf,int bufsize,ldap_pvt_thread_t thread)62092cfeba6Schristos thread_name( char *buf, int bufsize, ldap_pvt_thread_t thread )
62192cfeba6Schristos {
62292cfeba6Schristos int i;
62392cfeba6Schristos --bufsize;
62492cfeba6Schristos if( bufsize > 2*sizeof(thread) )
62592cfeba6Schristos bufsize = 2*sizeof(thread);
62692cfeba6Schristos for( i = 0; i < bufsize; i += 2 )
62792cfeba6Schristos snprintf( buf+i, 3, "%02x", ((unsigned char *)&thread)[i/2] );
62892cfeba6Schristos return buf;
62992cfeba6Schristos }
63092cfeba6Schristos
63192cfeba6Schristos
63292cfeba6Schristos /* Add <adjust> (+/-1) to resource count <which> unless "nocount". */
63392cfeba6Schristos static void
adjust_count(int which,int adjust)63492cfeba6Schristos adjust_count( int which, int adjust )
63592cfeba6Schristos {
63692cfeba6Schristos int rc;
63792cfeba6Schristos switch( count ) {
63892cfeba6Schristos case Count_no:
63992cfeba6Schristos break;
64092cfeba6Schristos case Count_yes:
64192cfeba6Schristos rc = ldap_int_thread_mutex_lock( &resource_mutexes[which] );
64292cfeba6Schristos assert( rc == 0 );
64392cfeba6Schristos resource_counts[which] += adjust;
64492cfeba6Schristos rc = ldap_int_thread_mutex_unlock( &resource_mutexes[which] );
64592cfeba6Schristos assert( rc == 0 );
64692cfeba6Schristos break;
64792cfeba6Schristos case Count_reported:
64892cfeba6Schristos fputs( "== thr_debug: More thread activity after exit ==\n", stderr );
64992cfeba6Schristos count = Count_reported_more;
65092cfeba6Schristos /* FALL THROUGH */
65192cfeba6Schristos case Count_reported_more:
65292cfeba6Schristos /* Not used, but result might be inspected with debugger */
65392cfeba6Schristos /* (Hopefully threading is disabled by now...) */
65492cfeba6Schristos resource_counts[which] += adjust;
65592cfeba6Schristos break;
65692cfeba6Schristos }
65792cfeba6Schristos }
65892cfeba6Schristos
65992cfeba6Schristos
66092cfeba6Schristos /* Wrappers for LDAP_THREAD_IMPLEMENTATION: */
66192cfeba6Schristos
66292cfeba6Schristos /* Used instead of ldap_int_thread_initialize by ldap_pvt_thread_initialize */
66392cfeba6Schristos int
ldap_debug_thread_initialize(void)66492cfeba6Schristos ldap_debug_thread_initialize( void )
66592cfeba6Schristos {
66692cfeba6Schristos int i, rc, rc2;
66792cfeba6Schristos if( !options_done )
66892cfeba6Schristos get_options();
66992cfeba6Schristos ERROR_IF( threading_enabled, "ldap_debug_thread_initialize" );
67092cfeba6Schristos threading_enabled = 1;
67192cfeba6Schristos rc = ldap_int_thread_initialize();
67292cfeba6Schristos if( rc ) {
67392cfeba6Schristos ERROR( rc, "ldap_debug_thread_initialize:threads" );
67492cfeba6Schristos threading_enabled = 0;
67592cfeba6Schristos } else {
67692cfeba6Schristos init_thread_info();
67792cfeba6Schristos if( count != Count_no ) {
67892cfeba6Schristos for( i = rc2 = 0; i < Idx_max; i++ )
67992cfeba6Schristos rc2 |= ldap_int_thread_mutex_init( &resource_mutexes[i] );
68092cfeba6Schristos assert( rc2 == 0 );
68192cfeba6Schristos /* FIXME: Only for static libldap as in init.c? If so, why? */
68292cfeba6Schristos atexit( count_resource_leaks );
68392cfeba6Schristos }
68492cfeba6Schristos }
68592cfeba6Schristos return rc;
68692cfeba6Schristos }
68792cfeba6Schristos
68892cfeba6Schristos /* Used instead of ldap_int_thread_destroy by ldap_pvt_thread_destroy */
68992cfeba6Schristos int
ldap_debug_thread_destroy(void)69092cfeba6Schristos ldap_debug_thread_destroy( void )
69192cfeba6Schristos {
69292cfeba6Schristos int rc;
69392cfeba6Schristos ERROR_IF( !threading_enabled, "ldap_debug_thread_destroy" );
69492cfeba6Schristos /* sleep(1) -- need to wait for thread pool to finish? */
69592cfeba6Schristos rc = ldap_int_thread_destroy();
69692cfeba6Schristos if( rc ) {
69792cfeba6Schristos ERROR( rc, "ldap_debug_thread_destroy:threads" );
69892cfeba6Schristos } else {
69992cfeba6Schristos threading_enabled = 0;
70092cfeba6Schristos }
70192cfeba6Schristos return rc;
70292cfeba6Schristos }
70392cfeba6Schristos
70492cfeba6Schristos int
ldap_pvt_thread_set_concurrency(int n)70592cfeba6Schristos ldap_pvt_thread_set_concurrency( int n )
70692cfeba6Schristos {
70792cfeba6Schristos int rc;
70892cfeba6Schristos ERROR_IF( !threading_enabled, "ldap_pvt_thread_set_concurrency" );
70992cfeba6Schristos rc = ldap_int_thread_set_concurrency( n );
71092cfeba6Schristos ERROR_IF( rc, "ldap_pvt_thread_set_concurrency" );
71192cfeba6Schristos return rc;
71292cfeba6Schristos }
71392cfeba6Schristos
71492cfeba6Schristos int
ldap_pvt_thread_get_concurrency(void)71592cfeba6Schristos ldap_pvt_thread_get_concurrency( void )
71692cfeba6Schristos {
71792cfeba6Schristos int rc;
71892cfeba6Schristos ERROR_IF( !threading_enabled, "ldap_pvt_thread_get_concurrency" );
71992cfeba6Schristos rc = ldap_int_thread_get_concurrency();
72092cfeba6Schristos ERROR_IF( rc, "ldap_pvt_thread_get_concurrency" );
72192cfeba6Schristos return rc;
72292cfeba6Schristos }
72392cfeba6Schristos
72492cfeba6Schristos unsigned int
ldap_pvt_thread_sleep(unsigned int interval)72592cfeba6Schristos ldap_pvt_thread_sleep( unsigned int interval )
72692cfeba6Schristos {
72792cfeba6Schristos int rc;
72892cfeba6Schristos ERROR_IF( !threading_enabled, "ldap_pvt_thread_sleep" );
72992cfeba6Schristos rc = ldap_int_thread_sleep( interval );
73092cfeba6Schristos ERROR_IF( rc, "ldap_pvt_thread_sleep" );
73192cfeba6Schristos return 0;
73292cfeba6Schristos }
73392cfeba6Schristos
73492cfeba6Schristos static void
thread_exiting(const char * how,const char * msg)73592cfeba6Schristos thread_exiting( const char *how, const char *msg )
73692cfeba6Schristos {
73792cfeba6Schristos ldap_pvt_thread_t thread;
73892cfeba6Schristos #if 0 /* Detached threads may exit after ldap_debug_thread_destroy(). */
73992cfeba6Schristos ERROR_IF( !threading_enabled, msg );
74092cfeba6Schristos #endif
74192cfeba6Schristos thread = ldap_pvt_thread_self();
74292cfeba6Schristos if( tracethreads ) {
74392cfeba6Schristos char buf[40];
74492cfeba6Schristos fprintf( stderr, "== thr_debug: %s thread %s ==\n",
74592cfeba6Schristos how, thread_name( buf, sizeof(buf), thread ) );
74692cfeba6Schristos }
74792cfeba6Schristos if( threadID ) {
74892cfeba6Schristos with_thread_info_lock({
74992cfeba6Schristos ldap_debug_thread_t *t = get_thread_info( thread, msg );
75092cfeba6Schristos if( thread_info_detached( t ) )
75192cfeba6Schristos remove_thread_info( t, msg );
75292cfeba6Schristos });
75392cfeba6Schristos }
75492cfeba6Schristos adjust_count( Idx_unexited_thread, -1 );
75592cfeba6Schristos }
75692cfeba6Schristos
75792cfeba6Schristos void
ldap_pvt_thread_exit(void * retval)75892cfeba6Schristos ldap_pvt_thread_exit( void *retval )
75992cfeba6Schristos {
76092cfeba6Schristos thread_exiting( "Exiting", "ldap_pvt_thread_exit" );
76192cfeba6Schristos ldap_int_thread_exit( retval );
76292cfeba6Schristos }
76392cfeba6Schristos
76492cfeba6Schristos typedef struct {
76592cfeba6Schristos void *(*start_routine)( void * );
76692cfeba6Schristos void *arg;
76792cfeba6Schristos } ldap_debug_thread_call_t;
76892cfeba6Schristos
76992cfeba6Schristos static void *
ldap_debug_thread_wrapper(void * arg)77092cfeba6Schristos ldap_debug_thread_wrapper( void *arg )
77192cfeba6Schristos {
77292cfeba6Schristos void *ret;
77392cfeba6Schristos ldap_debug_thread_call_t call = *(ldap_debug_thread_call_t *)arg;
77492cfeba6Schristos free( arg );
77592cfeba6Schristos ret = call.start_routine( call.arg );
77692cfeba6Schristos thread_exiting( "Returning from", "ldap_debug_thread_wrapper" );
77792cfeba6Schristos return ret;
77892cfeba6Schristos }
77992cfeba6Schristos
78092cfeba6Schristos int
ldap_pvt_thread_create(ldap_pvt_thread_t * thread,int detach,void * (* start_routine)(void *),void * arg)78192cfeba6Schristos ldap_pvt_thread_create(
78292cfeba6Schristos ldap_pvt_thread_t *thread,
78392cfeba6Schristos int detach,
78492cfeba6Schristos void *(*start_routine)( void * ),
78592cfeba6Schristos void *arg )
78692cfeba6Schristos {
78792cfeba6Schristos int rc;
78892cfeba6Schristos if( !options_done )
78992cfeba6Schristos get_options();
79092cfeba6Schristos ERROR_IF( !threading_enabled, "ldap_pvt_thread_create" );
79192cfeba6Schristos
79292cfeba6Schristos if( wrap_threads ) {
79392cfeba6Schristos ldap_debug_thread_call_t *call = malloc(
79492cfeba6Schristos sizeof( ldap_debug_thread_call_t ) );
79592cfeba6Schristos assert( call != NULL );
79692cfeba6Schristos call->start_routine = start_routine;
79792cfeba6Schristos call->arg = arg;
79892cfeba6Schristos start_routine = ldap_debug_thread_wrapper;
79992cfeba6Schristos arg = call;
80092cfeba6Schristos }
80192cfeba6Schristos if( threadID ) {
80292cfeba6Schristos with_thread_info_lock({
80392cfeba6Schristos rc = ldap_int_thread_create( thread, detach, start_routine, arg );
80492cfeba6Schristos if( rc == 0 )
80592cfeba6Schristos add_thread_info( "ldap_pvt_thread_create", thread, detach );
80692cfeba6Schristos });
80792cfeba6Schristos } else {
80892cfeba6Schristos rc = ldap_int_thread_create( thread, detach, start_routine, arg );
80992cfeba6Schristos }
81092cfeba6Schristos if( rc ) {
81192cfeba6Schristos ERROR( rc, "ldap_pvt_thread_create" );
81292cfeba6Schristos if( wrap_threads )
81392cfeba6Schristos free( arg );
81492cfeba6Schristos } else {
81592cfeba6Schristos if( tracethreads ) {
81692cfeba6Schristos char buf[40], buf2[40];
81792cfeba6Schristos fprintf( stderr,
81892cfeba6Schristos "== thr_debug: Created thread %s%s from thread %s ==\n",
81992cfeba6Schristos thread_name( buf, sizeof(buf), *thread ),
82092cfeba6Schristos detach ? " (detached)" : "",
82192cfeba6Schristos thread_name( buf2, sizeof(buf2), ldap_pvt_thread_self() ) );
82292cfeba6Schristos }
82392cfeba6Schristos adjust_count( Idx_unexited_thread, +1 );
82492cfeba6Schristos if( !detach )
82592cfeba6Schristos adjust_count( Idx_unjoined_thread, +1 );
82692cfeba6Schristos }
82792cfeba6Schristos return rc;
82892cfeba6Schristos }
82992cfeba6Schristos
83092cfeba6Schristos int
ldap_pvt_thread_join(ldap_pvt_thread_t thread,void ** thread_return)83192cfeba6Schristos ldap_pvt_thread_join( ldap_pvt_thread_t thread, void **thread_return )
83292cfeba6Schristos {
83392cfeba6Schristos int rc;
83492cfeba6Schristos ldap_debug_thread_t *t = NULL;
83592cfeba6Schristos ERROR_IF( !threading_enabled, "ldap_pvt_thread_join" );
83692cfeba6Schristos if( tracethreads ) {
83792cfeba6Schristos char buf[40], buf2[40];
83892cfeba6Schristos fprintf( stderr, "== thr_debug: Joining thread %s in thread %s ==\n",
83992cfeba6Schristos thread_name( buf, sizeof(buf), thread ),
84092cfeba6Schristos thread_name( buf2, sizeof(buf2), ldap_pvt_thread_self() ) );
84192cfeba6Schristos }
84292cfeba6Schristos if( threadID )
84392cfeba6Schristos with_thread_info_lock( {
84492cfeba6Schristos t = get_thread_info( thread, "ldap_pvt_thread_join" );
84592cfeba6Schristos ERROR_IF( thread_info_detached( t ), "ldap_pvt_thread_join" );
84692cfeba6Schristos } );
84792cfeba6Schristos rc = ldap_int_thread_join( thread, thread_return );
84892cfeba6Schristos if( rc ) {
84992cfeba6Schristos ERROR( rc, "ldap_pvt_thread_join" );
85092cfeba6Schristos } else {
85192cfeba6Schristos if( threadID )
85292cfeba6Schristos with_thread_info_lock(
85392cfeba6Schristos remove_thread_info( t, "ldap_pvt_thread_join" ) );
85492cfeba6Schristos adjust_count( Idx_unjoined_thread, -1 );
85592cfeba6Schristos }
85692cfeba6Schristos
85792cfeba6Schristos return rc;
85892cfeba6Schristos }
85992cfeba6Schristos
86092cfeba6Schristos int
ldap_pvt_thread_kill(ldap_pvt_thread_t thread,int signo)86192cfeba6Schristos ldap_pvt_thread_kill( ldap_pvt_thread_t thread, int signo )
86292cfeba6Schristos {
86392cfeba6Schristos int rc;
86492cfeba6Schristos ERROR_IF( !threading_enabled, "ldap_pvt_thread_kill" );
86592cfeba6Schristos if( tracethreads ) {
86692cfeba6Schristos char buf[40], buf2[40];
86792cfeba6Schristos fprintf( stderr,
86892cfeba6Schristos "== thr_debug: Killing thread %s (sig %i) from thread %s ==\n",
86992cfeba6Schristos thread_name( buf, sizeof(buf), thread ), signo,
87092cfeba6Schristos thread_name( buf2, sizeof(buf2), ldap_pvt_thread_self() ) );
87192cfeba6Schristos }
87292cfeba6Schristos rc = ldap_int_thread_kill( thread, signo );
87392cfeba6Schristos ERROR_IF( rc, "ldap_pvt_thread_kill" );
87492cfeba6Schristos return rc;
87592cfeba6Schristos }
87692cfeba6Schristos
87792cfeba6Schristos int
ldap_pvt_thread_yield(void)87892cfeba6Schristos ldap_pvt_thread_yield( void )
87992cfeba6Schristos {
88092cfeba6Schristos int rc;
88192cfeba6Schristos ERROR_IF( !threading_enabled, "ldap_pvt_thread_yield" );
88292cfeba6Schristos rc = ldap_int_thread_yield();
88392cfeba6Schristos ERROR_IF( rc, "ldap_pvt_thread_yield" );
88492cfeba6Schristos return rc;
88592cfeba6Schristos }
88692cfeba6Schristos
88792cfeba6Schristos ldap_pvt_thread_t
ldap_pvt_thread_self(void)88892cfeba6Schristos ldap_pvt_thread_self( void )
88992cfeba6Schristos {
89092cfeba6Schristos #if 0 /* Function is used by ch_free() via slap_sl_contxt() in slapd */
89192cfeba6Schristos ERROR_IF( !threading_enabled, "ldap_pvt_thread_self" );
89292cfeba6Schristos #endif
89392cfeba6Schristos return ldap_int_thread_self();
89492cfeba6Schristos }
89592cfeba6Schristos
89692cfeba6Schristos int
ldap_pvt_thread_cond_init(ldap_pvt_thread_cond_t * cond)89792cfeba6Schristos ldap_pvt_thread_cond_init( ldap_pvt_thread_cond_t *cond )
89892cfeba6Schristos {
89992cfeba6Schristos int rc;
90092cfeba6Schristos init_usage( &cond->usage, "ldap_pvt_thread_cond_init" );
90192cfeba6Schristos rc = ldap_int_thread_cond_init( WRAPPED( cond ) );
90292cfeba6Schristos if( rc ) {
90392cfeba6Schristos ERROR( rc, "ldap_pvt_thread_cond_init" );
90492cfeba6Schristos destroy_usage( &cond->usage );
90592cfeba6Schristos } else {
90692cfeba6Schristos adjust_count( Idx_cond, +1 );
90792cfeba6Schristos }
90892cfeba6Schristos return rc;
90992cfeba6Schristos }
91092cfeba6Schristos
91192cfeba6Schristos int
ldap_pvt_thread_cond_destroy(ldap_pvt_thread_cond_t * cond)91292cfeba6Schristos ldap_pvt_thread_cond_destroy( ldap_pvt_thread_cond_t *cond )
91392cfeba6Schristos {
91492cfeba6Schristos int rc;
91592cfeba6Schristos check_usage( &cond->usage, "ldap_pvt_thread_cond_destroy" );
91692cfeba6Schristos rc = ldap_int_thread_cond_destroy( WRAPPED( cond ) );
91792cfeba6Schristos if( rc ) {
91892cfeba6Schristos ERROR( rc, "ldap_pvt_thread_cond_destroy" );
91992cfeba6Schristos } else {
92092cfeba6Schristos destroy_usage( &cond->usage );
92192cfeba6Schristos adjust_count( Idx_cond, -1 );
92292cfeba6Schristos }
92392cfeba6Schristos return rc;
92492cfeba6Schristos }
92592cfeba6Schristos
92692cfeba6Schristos int
ldap_pvt_thread_cond_signal(ldap_pvt_thread_cond_t * cond)92792cfeba6Schristos ldap_pvt_thread_cond_signal( ldap_pvt_thread_cond_t *cond )
92892cfeba6Schristos {
92992cfeba6Schristos int rc;
93092cfeba6Schristos check_usage( &cond->usage, "ldap_pvt_thread_cond_signal" );
93192cfeba6Schristos rc = ldap_int_thread_cond_signal( WRAPPED( cond ) );
93292cfeba6Schristos ERROR_IF( rc, "ldap_pvt_thread_cond_signal" );
93392cfeba6Schristos return rc;
93492cfeba6Schristos }
93592cfeba6Schristos
93692cfeba6Schristos int
ldap_pvt_thread_cond_broadcast(ldap_pvt_thread_cond_t * cond)93792cfeba6Schristos ldap_pvt_thread_cond_broadcast( ldap_pvt_thread_cond_t *cond )
93892cfeba6Schristos {
93992cfeba6Schristos int rc;
94092cfeba6Schristos check_usage( &cond->usage, "ldap_pvt_thread_cond_broadcast" );
94192cfeba6Schristos rc = ldap_int_thread_cond_broadcast( WRAPPED( cond ) );
94292cfeba6Schristos ERROR_IF( rc, "ldap_pvt_thread_cond_broadcast" );
94392cfeba6Schristos return rc;
94492cfeba6Schristos }
94592cfeba6Schristos
94692cfeba6Schristos int
ldap_pvt_thread_cond_wait(ldap_pvt_thread_cond_t * cond,ldap_pvt_thread_mutex_t * mutex)94792cfeba6Schristos ldap_pvt_thread_cond_wait(
94892cfeba6Schristos ldap_pvt_thread_cond_t *cond,
94992cfeba6Schristos ldap_pvt_thread_mutex_t *mutex )
95092cfeba6Schristos {
95192cfeba6Schristos int rc;
95292cfeba6Schristos ldap_int_thread_t owner;
95392cfeba6Schristos check_usage( &cond->usage, "ldap_pvt_thread_cond_wait:cond" );
95492cfeba6Schristos check_usage( &mutex->usage, "ldap_pvt_thread_cond_wait:mutex" );
95592cfeba6Schristos adjust_count( Idx_locked_mutex, -1 );
95692cfeba6Schristos owner = GET_OWNER( mutex );
95792cfeba6Schristos ASSERT_OWNER( mutex, "ldap_pvt_thread_cond_wait" );
95892cfeba6Schristos RESET_OWNER( mutex );
95992cfeba6Schristos rc = ldap_int_thread_cond_wait( WRAPPED( cond ), WRAPPED( mutex ) );
96092cfeba6Schristos ASSERT_NO_OWNER( mutex, "ldap_pvt_thread_cond_wait" );
96192cfeba6Schristos SET_OWNER( mutex, rc ? owner : ldap_int_thread_self() );
96292cfeba6Schristos adjust_count( Idx_locked_mutex, +1 );
96392cfeba6Schristos ERROR_IF( rc, "ldap_pvt_thread_cond_wait" );
96492cfeba6Schristos return rc;
96592cfeba6Schristos }
96692cfeba6Schristos
96792cfeba6Schristos int
ldap_pvt_thread_mutex_recursive_init(ldap_pvt_thread_mutex_t * mutex)96892cfeba6Schristos ldap_pvt_thread_mutex_recursive_init( ldap_pvt_thread_mutex_t *mutex )
96992cfeba6Schristos {
97092cfeba6Schristos int rc;
97192cfeba6Schristos init_usage( &mutex->usage, "ldap_pvt_thread_mutex_recursive_init" );
97292cfeba6Schristos rc = ldap_int_thread_mutex_recursive_init( WRAPPED( mutex ) );
97392cfeba6Schristos if( rc ) {
97492cfeba6Schristos ERROR( rc, "ldap_pvt_thread_mutex_recursive_init" );
97592cfeba6Schristos destroy_usage( &mutex->usage );
97692cfeba6Schristos } else {
97792cfeba6Schristos RESET_OWNER( mutex );
97892cfeba6Schristos adjust_count( Idx_mutex, +1 );
97992cfeba6Schristos }
98092cfeba6Schristos return rc;
98192cfeba6Schristos }
98292cfeba6Schristos
98392cfeba6Schristos int
ldap_pvt_thread_mutex_init(ldap_pvt_thread_mutex_t * mutex)98492cfeba6Schristos ldap_pvt_thread_mutex_init( ldap_pvt_thread_mutex_t *mutex )
98592cfeba6Schristos {
98692cfeba6Schristos int rc;
98792cfeba6Schristos init_usage( &mutex->usage, "ldap_pvt_thread_mutex_init" );
98892cfeba6Schristos rc = ldap_int_thread_mutex_init( WRAPPED( mutex ) );
98992cfeba6Schristos if( rc ) {
99092cfeba6Schristos ERROR( rc, "ldap_pvt_thread_mutex_init" );
99192cfeba6Schristos destroy_usage( &mutex->usage );
99292cfeba6Schristos } else {
99392cfeba6Schristos RESET_OWNER( mutex );
99492cfeba6Schristos adjust_count( Idx_mutex, +1 );
99592cfeba6Schristos }
99692cfeba6Schristos return rc;
99792cfeba6Schristos }
99892cfeba6Schristos
99992cfeba6Schristos int
ldap_pvt_thread_mutex_destroy(ldap_pvt_thread_mutex_t * mutex)100092cfeba6Schristos ldap_pvt_thread_mutex_destroy( ldap_pvt_thread_mutex_t *mutex )
100192cfeba6Schristos {
100292cfeba6Schristos int rc;
100392cfeba6Schristos check_usage( &mutex->usage, "ldap_pvt_thread_mutex_destroy" );
100492cfeba6Schristos ASSERT_NO_OWNER( mutex, "ldap_pvt_thread_mutex_destroy" );
100592cfeba6Schristos rc = ldap_int_thread_mutex_destroy( WRAPPED( mutex ) );
100692cfeba6Schristos if( rc ) {
100792cfeba6Schristos ERROR( rc, "ldap_pvt_thread_mutex_destroy" );
100892cfeba6Schristos } else {
100992cfeba6Schristos destroy_usage( &mutex->usage );
101092cfeba6Schristos RESET_OWNER( mutex );
101192cfeba6Schristos adjust_count( Idx_mutex, -1 );
101292cfeba6Schristos }
101392cfeba6Schristos return rc;
101492cfeba6Schristos }
101592cfeba6Schristos
101692cfeba6Schristos int
ldap_pvt_thread_mutex_lock(ldap_pvt_thread_mutex_t * mutex)101792cfeba6Schristos ldap_pvt_thread_mutex_lock( ldap_pvt_thread_mutex_t *mutex )
101892cfeba6Schristos {
101992cfeba6Schristos int rc;
102092cfeba6Schristos check_usage( &mutex->usage, "ldap_pvt_thread_mutex_lock" );
102192cfeba6Schristos rc = ldap_int_thread_mutex_lock( WRAPPED( mutex ) );
102292cfeba6Schristos if( rc ) {
102392cfeba6Schristos ERROR_IF( rc, "ldap_pvt_thread_mutex_lock" );
102492cfeba6Schristos } else {
102592cfeba6Schristos ASSERT_NO_OWNER( mutex, "ldap_pvt_thread_mutex_lock" );
102692cfeba6Schristos SET_OWNER( mutex, ldap_int_thread_self() );
102792cfeba6Schristos adjust_count( Idx_locked_mutex, +1 );
102892cfeba6Schristos }
102992cfeba6Schristos return rc;
103092cfeba6Schristos }
103192cfeba6Schristos
103292cfeba6Schristos int
ldap_pvt_thread_mutex_trylock(ldap_pvt_thread_mutex_t * mutex)103392cfeba6Schristos ldap_pvt_thread_mutex_trylock( ldap_pvt_thread_mutex_t *mutex )
103492cfeba6Schristos {
103592cfeba6Schristos int rc;
103692cfeba6Schristos check_usage( &mutex->usage, "ldap_pvt_thread_mutex_trylock" );
103792cfeba6Schristos rc = ldap_int_thread_mutex_trylock( WRAPPED( mutex ) );
103892cfeba6Schristos if( rc == 0 ) {
103992cfeba6Schristos ASSERT_NO_OWNER( mutex, "ldap_pvt_thread_mutex_trylock" );
104092cfeba6Schristos SET_OWNER( mutex, ldap_int_thread_self() );
104192cfeba6Schristos adjust_count( Idx_locked_mutex, +1 );
104292cfeba6Schristos }
104392cfeba6Schristos return rc;
104492cfeba6Schristos }
104592cfeba6Schristos
104692cfeba6Schristos int
ldap_pvt_thread_mutex_unlock(ldap_pvt_thread_mutex_t * mutex)104792cfeba6Schristos ldap_pvt_thread_mutex_unlock( ldap_pvt_thread_mutex_t *mutex )
104892cfeba6Schristos {
104992cfeba6Schristos int rc;
105092cfeba6Schristos check_usage( &mutex->usage, "ldap_pvt_thread_mutex_unlock" );
105192cfeba6Schristos ASSERT_OWNER( mutex, "ldap_pvt_thread_mutex_unlock" );
105292cfeba6Schristos RESET_OWNER( mutex ); /* Breaks if this thread did not own the mutex */
105392cfeba6Schristos rc = ldap_int_thread_mutex_unlock( WRAPPED( mutex ) );
105492cfeba6Schristos if( rc ) {
105592cfeba6Schristos ERROR_IF( rc, "ldap_pvt_thread_mutex_unlock" );
105692cfeba6Schristos } else {
105792cfeba6Schristos adjust_count( Idx_locked_mutex, -1 );
105892cfeba6Schristos }
105992cfeba6Schristos return rc;
106092cfeba6Schristos }
106192cfeba6Schristos
106292cfeba6Schristos
106392cfeba6Schristos /* Wrappers for LDAP_THREAD_RDWR_IMPLEMENTATION: */
106492cfeba6Schristos
106592cfeba6Schristos int
ldap_pvt_thread_rdwr_init(ldap_pvt_thread_rdwr_t * rwlock)106692cfeba6Schristos ldap_pvt_thread_rdwr_init( ldap_pvt_thread_rdwr_t *rwlock )
106792cfeba6Schristos {
106892cfeba6Schristos int rc;
106992cfeba6Schristos init_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_init" );
107092cfeba6Schristos rc = ldap_int_thread_rdwr_init( WRAPPED( rwlock ) );
107192cfeba6Schristos if( rc ) {
107292cfeba6Schristos ERROR( rc, "ldap_pvt_thread_rdwr_init" );
107392cfeba6Schristos destroy_usage( &rwlock->usage );
107492cfeba6Schristos } else {
107592cfeba6Schristos adjust_count( Idx_rdwr, +1 );
107692cfeba6Schristos }
107792cfeba6Schristos return rc;
107892cfeba6Schristos }
107992cfeba6Schristos
108092cfeba6Schristos int
ldap_pvt_thread_rdwr_destroy(ldap_pvt_thread_rdwr_t * rwlock)108192cfeba6Schristos ldap_pvt_thread_rdwr_destroy( ldap_pvt_thread_rdwr_t *rwlock )
108292cfeba6Schristos {
108392cfeba6Schristos int rc;
108492cfeba6Schristos check_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_destroy" );
108592cfeba6Schristos rc = ldap_int_thread_rdwr_destroy( WRAPPED( rwlock ) );
108692cfeba6Schristos if( rc ) {
108792cfeba6Schristos ERROR( rc, "ldap_pvt_thread_rdwr_destroy" );
108892cfeba6Schristos } else {
108992cfeba6Schristos destroy_usage( &rwlock->usage );
109092cfeba6Schristos adjust_count( Idx_rdwr, -1 );
109192cfeba6Schristos }
109292cfeba6Schristos return rc;
109392cfeba6Schristos }
109492cfeba6Schristos
109592cfeba6Schristos int
ldap_pvt_thread_rdwr_rlock(ldap_pvt_thread_rdwr_t * rwlock)109692cfeba6Schristos ldap_pvt_thread_rdwr_rlock( ldap_pvt_thread_rdwr_t *rwlock )
109792cfeba6Schristos {
109892cfeba6Schristos int rc;
109992cfeba6Schristos check_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_rlock" );
110092cfeba6Schristos rc = ldap_int_thread_rdwr_rlock( WRAPPED( rwlock ) );
110192cfeba6Schristos ERROR_IF( rc, "ldap_pvt_thread_rdwr_rlock" );
110292cfeba6Schristos return rc;
110392cfeba6Schristos }
110492cfeba6Schristos
110592cfeba6Schristos int
ldap_pvt_thread_rdwr_rtrylock(ldap_pvt_thread_rdwr_t * rwlock)110692cfeba6Schristos ldap_pvt_thread_rdwr_rtrylock( ldap_pvt_thread_rdwr_t *rwlock )
110792cfeba6Schristos {
110892cfeba6Schristos check_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_rtrylock" );
110992cfeba6Schristos return ldap_int_thread_rdwr_rtrylock( WRAPPED( rwlock ) );
111092cfeba6Schristos }
111192cfeba6Schristos
111292cfeba6Schristos int
ldap_pvt_thread_rdwr_runlock(ldap_pvt_thread_rdwr_t * rwlock)111392cfeba6Schristos ldap_pvt_thread_rdwr_runlock( ldap_pvt_thread_rdwr_t *rwlock )
111492cfeba6Schristos {
111592cfeba6Schristos int rc;
111692cfeba6Schristos check_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_runlock" );
111792cfeba6Schristos rc = ldap_int_thread_rdwr_runlock( WRAPPED( rwlock ) );
111892cfeba6Schristos ERROR_IF( rc, "ldap_pvt_thread_rdwr_runlock" );
111992cfeba6Schristos return rc;
112092cfeba6Schristos }
112192cfeba6Schristos
112292cfeba6Schristos int
ldap_pvt_thread_rdwr_wlock(ldap_pvt_thread_rdwr_t * rwlock)112392cfeba6Schristos ldap_pvt_thread_rdwr_wlock( ldap_pvt_thread_rdwr_t *rwlock )
112492cfeba6Schristos {
112592cfeba6Schristos int rc;
112692cfeba6Schristos check_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_wlock" );
112792cfeba6Schristos rc = ldap_int_thread_rdwr_wlock( WRAPPED( rwlock ) );
112892cfeba6Schristos ERROR_IF( rc, "ldap_pvt_thread_rdwr_wlock" );
112992cfeba6Schristos return rc;
113092cfeba6Schristos }
113192cfeba6Schristos
113292cfeba6Schristos int
ldap_pvt_thread_rdwr_wtrylock(ldap_pvt_thread_rdwr_t * rwlock)113392cfeba6Schristos ldap_pvt_thread_rdwr_wtrylock( ldap_pvt_thread_rdwr_t *rwlock )
113492cfeba6Schristos {
113592cfeba6Schristos check_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_wtrylock" );
113692cfeba6Schristos return ldap_int_thread_rdwr_wtrylock( WRAPPED( rwlock ) );
113792cfeba6Schristos }
113892cfeba6Schristos
113992cfeba6Schristos int
ldap_pvt_thread_rdwr_wunlock(ldap_pvt_thread_rdwr_t * rwlock)114092cfeba6Schristos ldap_pvt_thread_rdwr_wunlock( ldap_pvt_thread_rdwr_t *rwlock )
114192cfeba6Schristos {
114292cfeba6Schristos int rc;
114392cfeba6Schristos check_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_wunlock" );
114492cfeba6Schristos rc = ldap_int_thread_rdwr_wunlock( WRAPPED( rwlock ) );
114592cfeba6Schristos ERROR_IF( rc, "ldap_pvt_thread_rdwr_wunlock" );
114692cfeba6Schristos return rc;
114792cfeba6Schristos }
114892cfeba6Schristos
114992cfeba6Schristos #if defined(LDAP_RDWR_DEBUG) && !defined(LDAP_THREAD_HAVE_RDWR)
115092cfeba6Schristos
115192cfeba6Schristos int
ldap_pvt_thread_rdwr_readers(ldap_pvt_thread_rdwr_t * rwlock)115292cfeba6Schristos ldap_pvt_thread_rdwr_readers( ldap_pvt_thread_rdwr_t *rwlock )
115392cfeba6Schristos {
115492cfeba6Schristos check_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_readers" );
115592cfeba6Schristos return ldap_int_thread_rdwr_readers( WRAPPED( rwlock ) );
115692cfeba6Schristos }
115792cfeba6Schristos
115892cfeba6Schristos int
ldap_pvt_thread_rdwr_writers(ldap_pvt_thread_rdwr_t * rwlock)115992cfeba6Schristos ldap_pvt_thread_rdwr_writers( ldap_pvt_thread_rdwr_t *rwlock )
116092cfeba6Schristos {
116192cfeba6Schristos check_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_writers" );
116292cfeba6Schristos return ldap_int_thread_rdwr_writers( WRAPPED( rwlock ) );
116392cfeba6Schristos }
116492cfeba6Schristos
116592cfeba6Schristos int
ldap_pvt_thread_rdwr_active(ldap_pvt_thread_rdwr_t * rwlock)116692cfeba6Schristos ldap_pvt_thread_rdwr_active( ldap_pvt_thread_rdwr_t *rwlock )
116792cfeba6Schristos {
116892cfeba6Schristos check_usage( &rwlock->usage, "ldap_pvt_thread_rdwr_active" );
116992cfeba6Schristos return ldap_int_thread_rdwr_active( WRAPPED( rwlock ) );
117092cfeba6Schristos }
117192cfeba6Schristos
117292cfeba6Schristos #endif /* LDAP_RDWR_DEBUG && !LDAP_THREAD_HAVE_RDWR */
117392cfeba6Schristos
117492cfeba6Schristos
117592cfeba6Schristos /* Some wrappers for LDAP_THREAD_POOL_IMPLEMENTATION: */
117692cfeba6Schristos #ifdef LDAP_THREAD_POOL_IMPLEMENTATION
117792cfeba6Schristos
117892cfeba6Schristos int
ldap_pvt_thread_pool_init(ldap_pvt_thread_pool_t * tpool,int max_threads,int max_pending)117992cfeba6Schristos ldap_pvt_thread_pool_init(
118092cfeba6Schristos ldap_pvt_thread_pool_t *tpool,
118192cfeba6Schristos int max_threads,
118292cfeba6Schristos int max_pending )
118392cfeba6Schristos {
118492cfeba6Schristos int rc;
118592cfeba6Schristos if( !options_done )
118692cfeba6Schristos get_options();
118792cfeba6Schristos ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_init" );
118892cfeba6Schristos rc = ldap_int_thread_pool_init( tpool, max_threads, max_pending );
118992cfeba6Schristos if( rc ) {
119092cfeba6Schristos ERROR( rc, "ldap_pvt_thread_pool_init" );
119192cfeba6Schristos } else {
119292cfeba6Schristos adjust_count( Idx_tpool, +1 );
119392cfeba6Schristos }
119492cfeba6Schristos return rc;
119592cfeba6Schristos }
119692cfeba6Schristos
119792cfeba6Schristos int
ldap_pvt_thread_pool_submit(ldap_pvt_thread_pool_t * tpool,ldap_pvt_thread_start_t * start_routine,void * arg)119892cfeba6Schristos ldap_pvt_thread_pool_submit(
119992cfeba6Schristos ldap_pvt_thread_pool_t *tpool,
120092cfeba6Schristos ldap_pvt_thread_start_t *start_routine, void *arg )
120192cfeba6Schristos {
120292cfeba6Schristos int rc, has_pool;
120392cfeba6Schristos ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_submit" );
120492cfeba6Schristos has_pool = (tpool && *tpool);
120592cfeba6Schristos rc = ldap_int_thread_pool_submit( tpool, start_routine, arg );
120692cfeba6Schristos if( has_pool )
120792cfeba6Schristos ERROR_IF( rc, "ldap_pvt_thread_pool_submit" );
120892cfeba6Schristos return rc;
120992cfeba6Schristos }
121092cfeba6Schristos
121192cfeba6Schristos int
ldap_pvt_thread_pool_maxthreads(ldap_pvt_thread_pool_t * tpool,int max_threads)121292cfeba6Schristos ldap_pvt_thread_pool_maxthreads(
121392cfeba6Schristos ldap_pvt_thread_pool_t *tpool,
121492cfeba6Schristos int max_threads )
121592cfeba6Schristos {
121692cfeba6Schristos ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_maxthreads" );
121792cfeba6Schristos return ldap_int_thread_pool_maxthreads( tpool, max_threads );
121892cfeba6Schristos }
121992cfeba6Schristos
122092cfeba6Schristos int
ldap_pvt_thread_pool_backload(ldap_pvt_thread_pool_t * tpool)122192cfeba6Schristos ldap_pvt_thread_pool_backload( ldap_pvt_thread_pool_t *tpool )
122292cfeba6Schristos {
122392cfeba6Schristos ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_backload" );
122492cfeba6Schristos return ldap_int_thread_pool_backload( tpool );
122592cfeba6Schristos }
122692cfeba6Schristos
122792cfeba6Schristos int
ldap_pvt_thread_pool_destroy(ldap_pvt_thread_pool_t * tpool,int run_pending)122892cfeba6Schristos ldap_pvt_thread_pool_destroy( ldap_pvt_thread_pool_t *tpool, int run_pending )
122992cfeba6Schristos {
123092cfeba6Schristos int rc, has_pool;
123192cfeba6Schristos ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_destroy" );
123292cfeba6Schristos has_pool = (tpool && *tpool);
123392cfeba6Schristos rc = ldap_int_thread_pool_destroy( tpool, run_pending );
123492cfeba6Schristos if( has_pool ) {
123592cfeba6Schristos if( rc ) {
123692cfeba6Schristos ERROR( rc, "ldap_pvt_thread_pool_destroy" );
123792cfeba6Schristos } else {
123892cfeba6Schristos adjust_count( Idx_tpool, -1 );
123992cfeba6Schristos }
124092cfeba6Schristos }
124192cfeba6Schristos return rc;
124292cfeba6Schristos }
124392cfeba6Schristos
124492cfeba6Schristos int
ldap_pvt_thread_pool_close(ldap_pvt_thread_pool_t * tpool,int run_pending)124592cfeba6Schristos ldap_pvt_thread_pool_close( ldap_pvt_thread_pool_t *tpool, int run_pending )
124692cfeba6Schristos {
124792cfeba6Schristos int rc, has_pool;
124892cfeba6Schristos ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_close" );
124992cfeba6Schristos has_pool = (tpool && *tpool);
125092cfeba6Schristos rc = ldap_int_thread_pool_close( tpool, run_pending );
125192cfeba6Schristos if( has_pool && rc ) {
125292cfeba6Schristos ERROR( rc, "ldap_pvt_thread_pool_close" );
125392cfeba6Schristos }
125492cfeba6Schristos return rc;
125592cfeba6Schristos }
125692cfeba6Schristos
125792cfeba6Schristos int
ldap_pvt_thread_pool_free(ldap_pvt_thread_pool_t * tpool)125892cfeba6Schristos ldap_pvt_thread_pool_free( ldap_pvt_thread_pool_t *tpool )
125992cfeba6Schristos {
126092cfeba6Schristos int rc, has_pool;
126192cfeba6Schristos ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_free" );
126292cfeba6Schristos has_pool = (tpool && *tpool);
126392cfeba6Schristos rc = ldap_int_thread_pool_free( tpool );
126492cfeba6Schristos if( has_pool ) {
126592cfeba6Schristos if( rc ) {
126692cfeba6Schristos ERROR( rc, "ldap_pvt_thread_pool_free" );
126792cfeba6Schristos } else {
126892cfeba6Schristos adjust_count( Idx_tpool, -1 );
126992cfeba6Schristos }
127092cfeba6Schristos }
127192cfeba6Schristos return rc;
127292cfeba6Schristos }
127392cfeba6Schristos
127492cfeba6Schristos int
ldap_pvt_thread_pool_pause(ldap_pvt_thread_pool_t * tpool)127592cfeba6Schristos ldap_pvt_thread_pool_pause( ldap_pvt_thread_pool_t *tpool )
127692cfeba6Schristos {
127792cfeba6Schristos ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_pause" );
127892cfeba6Schristos return ldap_int_thread_pool_pause( tpool );
127992cfeba6Schristos }
128092cfeba6Schristos
128192cfeba6Schristos int
ldap_pvt_thread_pool_resume(ldap_pvt_thread_pool_t * tpool)128292cfeba6Schristos ldap_pvt_thread_pool_resume( ldap_pvt_thread_pool_t *tpool )
128392cfeba6Schristos {
128492cfeba6Schristos ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_resume" );
128592cfeba6Schristos return ldap_int_thread_pool_resume( tpool );
128692cfeba6Schristos }
128792cfeba6Schristos
128892cfeba6Schristos int
ldap_pvt_thread_pool_getkey(void * xctx,void * key,void ** data,ldap_pvt_thread_pool_keyfree_t ** kfree)128992cfeba6Schristos ldap_pvt_thread_pool_getkey(
129092cfeba6Schristos void *xctx,
129192cfeba6Schristos void *key,
129292cfeba6Schristos void **data,
129392cfeba6Schristos ldap_pvt_thread_pool_keyfree_t **kfree )
129492cfeba6Schristos {
129592cfeba6Schristos #if 0 /* Function is used by ch_free() via slap_sl_contxt() in slapd */
129692cfeba6Schristos ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_getkey" );
129792cfeba6Schristos #endif
129892cfeba6Schristos return ldap_int_thread_pool_getkey( xctx, key, data, kfree );
129992cfeba6Schristos }
130092cfeba6Schristos
130192cfeba6Schristos 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)130292cfeba6Schristos ldap_pvt_thread_pool_setkey(
130392cfeba6Schristos void *xctx,
130492cfeba6Schristos void *key,
130592cfeba6Schristos void *data,
130692cfeba6Schristos ldap_pvt_thread_pool_keyfree_t *kfree,
130792cfeba6Schristos void **olddatap,
130892cfeba6Schristos ldap_pvt_thread_pool_keyfree_t **oldkfreep )
130992cfeba6Schristos {
131092cfeba6Schristos int rc;
131192cfeba6Schristos ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_setkey" );
131292cfeba6Schristos rc = ldap_int_thread_pool_setkey(
131392cfeba6Schristos xctx, key, data, kfree, olddatap, oldkfreep );
131492cfeba6Schristos ERROR_IF( rc, "ldap_pvt_thread_pool_setkey" );
131592cfeba6Schristos return rc;
131692cfeba6Schristos }
131792cfeba6Schristos
131892cfeba6Schristos void
ldap_pvt_thread_pool_purgekey(void * key)131992cfeba6Schristos ldap_pvt_thread_pool_purgekey( void *key )
132092cfeba6Schristos {
132192cfeba6Schristos ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_purgekey" );
132292cfeba6Schristos ldap_int_thread_pool_purgekey( key );
132392cfeba6Schristos }
132492cfeba6Schristos
132592cfeba6Schristos void *
ldap_pvt_thread_pool_context(void)132692cfeba6Schristos ldap_pvt_thread_pool_context( void )
132792cfeba6Schristos {
132892cfeba6Schristos #if 0 /* Function is used by ch_free() via slap_sl_contxt() in slapd */
132992cfeba6Schristos ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_context" );
133092cfeba6Schristos #endif
133192cfeba6Schristos return ldap_int_thread_pool_context();
133292cfeba6Schristos }
133392cfeba6Schristos
133492cfeba6Schristos void
ldap_pvt_thread_pool_context_reset(void * vctx)133592cfeba6Schristos ldap_pvt_thread_pool_context_reset( void *vctx )
133692cfeba6Schristos {
133792cfeba6Schristos ERROR_IF( !threading_enabled, "ldap_pvt_thread_pool_context_reset" );
133892cfeba6Schristos ldap_int_thread_pool_context_reset( vctx );
133992cfeba6Schristos }
134092cfeba6Schristos
134192cfeba6Schristos #endif /* LDAP_THREAD_POOL_IMPLEMENTATION */
134292cfeba6Schristos
134392cfeba6Schristos #endif /* LDAP_THREAD_DEBUG */
1344