thr_debug.c 36 KB

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