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