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