1290001Sglebius/* 2290001Sglebius * Copyright (c) 2008-2012 Niels Provos, Nick Mathewson 3290001Sglebius * 4290001Sglebius * Redistribution and use in source and binary forms, with or without 5290001Sglebius * modification, are permitted provided that the following conditions 6290001Sglebius * are met: 7290001Sglebius * 1. Redistributions of source code must retain the above copyright 8290001Sglebius * notice, this list of conditions and the following disclaimer. 9290001Sglebius * 2. Redistributions in binary form must reproduce the above copyright 10290001Sglebius * notice, this list of conditions and the following disclaimer in the 11290001Sglebius * documentation and/or other materials provided with the distribution. 12290001Sglebius * 3. The name of the author may not be used to endorse or promote products 13290001Sglebius * derived from this software without specific prior written permission. 14290001Sglebius * 15290001Sglebius * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16290001Sglebius * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17290001Sglebius * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18290001Sglebius * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19290001Sglebius * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20290001Sglebius * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21290001Sglebius * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22290001Sglebius * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23290001Sglebius * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24290001Sglebius * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25290001Sglebius */ 26290001Sglebius#ifndef EVTHREAD_INTERNAL_H_INCLUDED_ 27290001Sglebius#define EVTHREAD_INTERNAL_H_INCLUDED_ 28290001Sglebius 29290001Sglebius#ifdef __cplusplus 30290001Sglebiusextern "C" { 31290001Sglebius#endif 32290001Sglebius 33290001Sglebius#include "event2/event-config.h" 34290001Sglebius#include "evconfig-private.h" 35290001Sglebius 36290001Sglebius#include "event2/thread.h" 37290001Sglebius#include "util-internal.h" 38290001Sglebius 39290001Sglebiusstruct event_base; 40290001Sglebius 41290001Sglebius#ifndef _WIN32 42290001Sglebius/* On Windows, the way we currently make DLLs, it's not allowed for us to 43290001Sglebius * have shared global structures. Thus, we only do the direct-call-to-function 44290001Sglebius * code path if we know that the local shared library system supports it. 45290001Sglebius */ 46290001Sglebius#define EVTHREAD_EXPOSE_STRUCTS 47290001Sglebius#endif 48290001Sglebius 49290001Sglebius#if ! defined(EVENT__DISABLE_THREAD_SUPPORT) && defined(EVTHREAD_EXPOSE_STRUCTS) 50290001Sglebius/* Global function pointers to lock-related functions. NULL if locking isn't 51290001Sglebius enabled. */ 52290001Sglebiusextern struct evthread_lock_callbacks evthread_lock_fns_; 53290001Sglebiusextern struct evthread_condition_callbacks evthread_cond_fns_; 54290001Sglebiusextern unsigned long (*evthread_id_fn_)(void); 55290001Sglebiusextern int evthread_lock_debugging_enabled_; 56290001Sglebius 57290001Sglebius/** Return the ID of the current thread, or 1 if threading isn't enabled. */ 58290001Sglebius#define EVTHREAD_GET_ID() \ 59290001Sglebius (evthread_id_fn_ ? evthread_id_fn_() : 1) 60290001Sglebius 61290001Sglebius/** Return true iff we're in the thread that is currently (or most recently) 62290001Sglebius * running a given event_base's loop. Requires lock. */ 63290001Sglebius#define EVBASE_IN_THREAD(base) \ 64290001Sglebius (evthread_id_fn_ == NULL || \ 65290001Sglebius (base)->th_owner_id == evthread_id_fn_()) 66290001Sglebius 67290001Sglebius/** Return true iff we need to notify the base's main thread about changes to 68290001Sglebius * its state, because it's currently running the main loop in another 69290001Sglebius * thread. Requires lock. */ 70290001Sglebius#define EVBASE_NEED_NOTIFY(base) \ 71290001Sglebius (evthread_id_fn_ != NULL && \ 72290001Sglebius (base)->running_loop && \ 73290001Sglebius (base)->th_owner_id != evthread_id_fn_()) 74290001Sglebius 75290001Sglebius/** Allocate a new lock, and store it in lockvar, a void*. Sets lockvar to 76290001Sglebius NULL if locking is not enabled. */ 77290001Sglebius#define EVTHREAD_ALLOC_LOCK(lockvar, locktype) \ 78290001Sglebius ((lockvar) = evthread_lock_fns_.alloc ? \ 79290001Sglebius evthread_lock_fns_.alloc(locktype) : NULL) 80290001Sglebius 81290001Sglebius/** Free a given lock, if it is present and locking is enabled. */ 82290001Sglebius#define EVTHREAD_FREE_LOCK(lockvar, locktype) \ 83290001Sglebius do { \ 84290001Sglebius void *lock_tmp_ = (lockvar); \ 85290001Sglebius if (lock_tmp_ && evthread_lock_fns_.free) \ 86290001Sglebius evthread_lock_fns_.free(lock_tmp_, (locktype)); \ 87290001Sglebius } while (0) 88290001Sglebius 89290001Sglebius/** Acquire a lock. */ 90290001Sglebius#define EVLOCK_LOCK(lockvar,mode) \ 91290001Sglebius do { \ 92290001Sglebius if (lockvar) \ 93290001Sglebius evthread_lock_fns_.lock(mode, lockvar); \ 94290001Sglebius } while (0) 95290001Sglebius 96290001Sglebius/** Release a lock */ 97290001Sglebius#define EVLOCK_UNLOCK(lockvar,mode) \ 98290001Sglebius do { \ 99290001Sglebius if (lockvar) \ 100290001Sglebius evthread_lock_fns_.unlock(mode, lockvar); \ 101290001Sglebius } while (0) 102290001Sglebius 103290001Sglebius/** Helper: put lockvar1 and lockvar2 into pointerwise ascending order. */ 104290001Sglebius#define EVLOCK_SORTLOCKS_(lockvar1, lockvar2) \ 105290001Sglebius do { \ 106290001Sglebius if (lockvar1 && lockvar2 && lockvar1 > lockvar2) { \ 107290001Sglebius void *tmp = lockvar1; \ 108290001Sglebius lockvar1 = lockvar2; \ 109290001Sglebius lockvar2 = tmp; \ 110290001Sglebius } \ 111290001Sglebius } while (0) 112290001Sglebius 113290001Sglebius/** Lock an event_base, if it is set up for locking. Acquires the lock 114290001Sglebius in the base structure whose field is named 'lockvar'. */ 115290001Sglebius#define EVBASE_ACQUIRE_LOCK(base, lockvar) do { \ 116290001Sglebius EVLOCK_LOCK((base)->lockvar, 0); \ 117290001Sglebius } while (0) 118290001Sglebius 119290001Sglebius/** Unlock an event_base, if it is set up for locking. */ 120290001Sglebius#define EVBASE_RELEASE_LOCK(base, lockvar) do { \ 121290001Sglebius EVLOCK_UNLOCK((base)->lockvar, 0); \ 122290001Sglebius } while (0) 123290001Sglebius 124290001Sglebius/** If lock debugging is enabled, and lock is non-null, assert that 'lock' is 125290001Sglebius * locked and held by us. */ 126290001Sglebius#define EVLOCK_ASSERT_LOCKED(lock) \ 127290001Sglebius do { \ 128290001Sglebius if ((lock) && evthread_lock_debugging_enabled_) { \ 129290001Sglebius EVUTIL_ASSERT(evthread_is_debug_lock_held_(lock)); \ 130290001Sglebius } \ 131290001Sglebius } while (0) 132290001Sglebius 133290001Sglebius/** Try to grab the lock for 'lockvar' without blocking, and return 1 if we 134290001Sglebius * manage to get it. */ 135290001Sglebiusstatic inline int EVLOCK_TRY_LOCK_(void *lock); 136290001Sglebiusstatic inline int 137290001SglebiusEVLOCK_TRY_LOCK_(void *lock) 138290001Sglebius{ 139290001Sglebius if (lock && evthread_lock_fns_.lock) { 140290001Sglebius int r = evthread_lock_fns_.lock(EVTHREAD_TRY, lock); 141290001Sglebius return !r; 142290001Sglebius } else { 143290001Sglebius /* Locking is disabled either globally or for this thing; 144290001Sglebius * of course we count as having the lock. */ 145290001Sglebius return 1; 146290001Sglebius } 147290001Sglebius} 148290001Sglebius 149290001Sglebius/** Allocate a new condition variable and store it in the void *, condvar */ 150290001Sglebius#define EVTHREAD_ALLOC_COND(condvar) \ 151290001Sglebius do { \ 152290001Sglebius (condvar) = evthread_cond_fns_.alloc_condition ? \ 153290001Sglebius evthread_cond_fns_.alloc_condition(0) : NULL; \ 154290001Sglebius } while (0) 155290001Sglebius/** Deallocate and free a condition variable in condvar */ 156290001Sglebius#define EVTHREAD_FREE_COND(cond) \ 157290001Sglebius do { \ 158290001Sglebius if (cond) \ 159290001Sglebius evthread_cond_fns_.free_condition((cond)); \ 160290001Sglebius } while (0) 161290001Sglebius/** Signal one thread waiting on cond */ 162290001Sglebius#define EVTHREAD_COND_SIGNAL(cond) \ 163290001Sglebius ( (cond) ? evthread_cond_fns_.signal_condition((cond), 0) : 0 ) 164290001Sglebius/** Signal all threads waiting on cond */ 165290001Sglebius#define EVTHREAD_COND_BROADCAST(cond) \ 166290001Sglebius ( (cond) ? evthread_cond_fns_.signal_condition((cond), 1) : 0 ) 167290001Sglebius/** Wait until the condition 'cond' is signalled. Must be called while 168290001Sglebius * holding 'lock'. The lock will be released until the condition is 169290001Sglebius * signalled, at which point it will be acquired again. Returns 0 for 170290001Sglebius * success, -1 for failure. */ 171290001Sglebius#define EVTHREAD_COND_WAIT(cond, lock) \ 172290001Sglebius ( (cond) ? evthread_cond_fns_.wait_condition((cond), (lock), NULL) : 0 ) 173290001Sglebius/** As EVTHREAD_COND_WAIT, but gives up after 'tv' has elapsed. Returns 1 174290001Sglebius * on timeout. */ 175290001Sglebius#define EVTHREAD_COND_WAIT_TIMED(cond, lock, tv) \ 176290001Sglebius ( (cond) ? evthread_cond_fns_.wait_condition((cond), (lock), (tv)) : 0 ) 177290001Sglebius 178290001Sglebius/** True iff locking functions have been configured. */ 179290001Sglebius#define EVTHREAD_LOCKING_ENABLED() \ 180290001Sglebius (evthread_lock_fns_.lock != NULL) 181290001Sglebius 182290001Sglebius#elif ! defined(EVENT__DISABLE_THREAD_SUPPORT) 183290001Sglebius 184290001Sglebiusunsigned long evthreadimpl_get_id_(void); 185290001Sglebiusint evthreadimpl_is_lock_debugging_enabled_(void); 186290001Sglebiusvoid *evthreadimpl_lock_alloc_(unsigned locktype); 187290001Sglebiusvoid evthreadimpl_lock_free_(void *lock, unsigned locktype); 188290001Sglebiusint evthreadimpl_lock_lock_(unsigned mode, void *lock); 189290001Sglebiusint evthreadimpl_lock_unlock_(unsigned mode, void *lock); 190290001Sglebiusvoid *evthreadimpl_cond_alloc_(unsigned condtype); 191290001Sglebiusvoid evthreadimpl_cond_free_(void *cond); 192290001Sglebiusint evthreadimpl_cond_signal_(void *cond, int broadcast); 193290001Sglebiusint evthreadimpl_cond_wait_(void *cond, void *lock, const struct timeval *tv); 194290001Sglebiusint evthreadimpl_locking_enabled_(void); 195290001Sglebius 196290001Sglebius#define EVTHREAD_GET_ID() evthreadimpl_get_id_() 197290001Sglebius#define EVBASE_IN_THREAD(base) \ 198290001Sglebius ((base)->th_owner_id == evthreadimpl_get_id_()) 199290001Sglebius#define EVBASE_NEED_NOTIFY(base) \ 200290001Sglebius ((base)->running_loop && \ 201290001Sglebius ((base)->th_owner_id != evthreadimpl_get_id_())) 202290001Sglebius 203290001Sglebius#define EVTHREAD_ALLOC_LOCK(lockvar, locktype) \ 204290001Sglebius ((lockvar) = evthreadimpl_lock_alloc_(locktype)) 205290001Sglebius 206290001Sglebius#define EVTHREAD_FREE_LOCK(lockvar, locktype) \ 207290001Sglebius do { \ 208290001Sglebius void *lock_tmp_ = (lockvar); \ 209290001Sglebius if (lock_tmp_) \ 210290001Sglebius evthreadimpl_lock_free_(lock_tmp_, (locktype)); \ 211290001Sglebius } while (0) 212290001Sglebius 213290001Sglebius/** Acquire a lock. */ 214290001Sglebius#define EVLOCK_LOCK(lockvar,mode) \ 215290001Sglebius do { \ 216290001Sglebius if (lockvar) \ 217290001Sglebius evthreadimpl_lock_lock_(mode, lockvar); \ 218290001Sglebius } while (0) 219290001Sglebius 220290001Sglebius/** Release a lock */ 221290001Sglebius#define EVLOCK_UNLOCK(lockvar,mode) \ 222290001Sglebius do { \ 223290001Sglebius if (lockvar) \ 224290001Sglebius evthreadimpl_lock_unlock_(mode, lockvar); \ 225290001Sglebius } while (0) 226290001Sglebius 227290001Sglebius/** Lock an event_base, if it is set up for locking. Acquires the lock 228290001Sglebius in the base structure whose field is named 'lockvar'. */ 229290001Sglebius#define EVBASE_ACQUIRE_LOCK(base, lockvar) do { \ 230290001Sglebius EVLOCK_LOCK((base)->lockvar, 0); \ 231290001Sglebius } while (0) 232290001Sglebius 233290001Sglebius/** Unlock an event_base, if it is set up for locking. */ 234290001Sglebius#define EVBASE_RELEASE_LOCK(base, lockvar) do { \ 235290001Sglebius EVLOCK_UNLOCK((base)->lockvar, 0); \ 236290001Sglebius } while (0) 237290001Sglebius 238290001Sglebius/** If lock debugging is enabled, and lock is non-null, assert that 'lock' is 239290001Sglebius * locked and held by us. */ 240290001Sglebius#define EVLOCK_ASSERT_LOCKED(lock) \ 241290001Sglebius do { \ 242290001Sglebius if ((lock) && evthreadimpl_is_lock_debugging_enabled_()) { \ 243290001Sglebius EVUTIL_ASSERT(evthread_is_debug_lock_held_(lock)); \ 244290001Sglebius } \ 245290001Sglebius } while (0) 246290001Sglebius 247290001Sglebius/** Try to grab the lock for 'lockvar' without blocking, and return 1 if we 248290001Sglebius * manage to get it. */ 249290001Sglebiusstatic inline int EVLOCK_TRY_LOCK_(void *lock); 250290001Sglebiusstatic inline int 251290001SglebiusEVLOCK_TRY_LOCK_(void *lock) 252290001Sglebius{ 253290001Sglebius if (lock) { 254290001Sglebius int r = evthreadimpl_lock_lock_(EVTHREAD_TRY, lock); 255290001Sglebius return !r; 256290001Sglebius } else { 257290001Sglebius /* Locking is disabled either globally or for this thing; 258290001Sglebius * of course we count as having the lock. */ 259290001Sglebius return 1; 260290001Sglebius } 261290001Sglebius} 262290001Sglebius 263290001Sglebius/** Allocate a new condition variable and store it in the void *, condvar */ 264290001Sglebius#define EVTHREAD_ALLOC_COND(condvar) \ 265290001Sglebius do { \ 266290001Sglebius (condvar) = evthreadimpl_cond_alloc_(0); \ 267290001Sglebius } while (0) 268290001Sglebius/** Deallocate and free a condition variable in condvar */ 269290001Sglebius#define EVTHREAD_FREE_COND(cond) \ 270290001Sglebius do { \ 271290001Sglebius if (cond) \ 272290001Sglebius evthreadimpl_cond_free_((cond)); \ 273290001Sglebius } while (0) 274290001Sglebius/** Signal one thread waiting on cond */ 275290001Sglebius#define EVTHREAD_COND_SIGNAL(cond) \ 276290001Sglebius ( (cond) ? evthreadimpl_cond_signal_((cond), 0) : 0 ) 277290001Sglebius/** Signal all threads waiting on cond */ 278290001Sglebius#define EVTHREAD_COND_BROADCAST(cond) \ 279290001Sglebius ( (cond) ? evthreadimpl_cond_signal_((cond), 1) : 0 ) 280290001Sglebius/** Wait until the condition 'cond' is signalled. Must be called while 281290001Sglebius * holding 'lock'. The lock will be released until the condition is 282290001Sglebius * signalled, at which point it will be acquired again. Returns 0 for 283290001Sglebius * success, -1 for failure. */ 284290001Sglebius#define EVTHREAD_COND_WAIT(cond, lock) \ 285290001Sglebius ( (cond) ? evthreadimpl_cond_wait_((cond), (lock), NULL) : 0 ) 286290001Sglebius/** As EVTHREAD_COND_WAIT, but gives up after 'tv' has elapsed. Returns 1 287290001Sglebius * on timeout. */ 288290001Sglebius#define EVTHREAD_COND_WAIT_TIMED(cond, lock, tv) \ 289290001Sglebius ( (cond) ? evthreadimpl_cond_wait_((cond), (lock), (tv)) : 0 ) 290290001Sglebius 291290001Sglebius#define EVTHREAD_LOCKING_ENABLED() \ 292290001Sglebius (evthreadimpl_locking_enabled_()) 293290001Sglebius 294290001Sglebius#else /* EVENT__DISABLE_THREAD_SUPPORT */ 295290001Sglebius 296290001Sglebius#define EVTHREAD_GET_ID() 1 297290001Sglebius#define EVTHREAD_ALLOC_LOCK(lockvar, locktype) EVUTIL_NIL_STMT_ 298290001Sglebius#define EVTHREAD_FREE_LOCK(lockvar, locktype) EVUTIL_NIL_STMT_ 299290001Sglebius 300290001Sglebius#define EVLOCK_LOCK(lockvar, mode) EVUTIL_NIL_STMT_ 301290001Sglebius#define EVLOCK_UNLOCK(lockvar, mode) EVUTIL_NIL_STMT_ 302290001Sglebius#define EVLOCK_LOCK2(lock1,lock2,mode1,mode2) EVUTIL_NIL_STMT_ 303290001Sglebius#define EVLOCK_UNLOCK2(lock1,lock2,mode1,mode2) EVUTIL_NIL_STMT_ 304290001Sglebius 305290001Sglebius#define EVBASE_IN_THREAD(base) 1 306290001Sglebius#define EVBASE_NEED_NOTIFY(base) 0 307290001Sglebius#define EVBASE_ACQUIRE_LOCK(base, lock) EVUTIL_NIL_STMT_ 308290001Sglebius#define EVBASE_RELEASE_LOCK(base, lock) EVUTIL_NIL_STMT_ 309290001Sglebius#define EVLOCK_ASSERT_LOCKED(lock) EVUTIL_NIL_STMT_ 310290001Sglebius 311290001Sglebius#define EVLOCK_TRY_LOCK_(lock) 1 312290001Sglebius 313290001Sglebius#define EVTHREAD_ALLOC_COND(condvar) EVUTIL_NIL_STMT_ 314290001Sglebius#define EVTHREAD_FREE_COND(cond) EVUTIL_NIL_STMT_ 315290001Sglebius#define EVTHREAD_COND_SIGNAL(cond) EVUTIL_NIL_STMT_ 316290001Sglebius#define EVTHREAD_COND_BROADCAST(cond) EVUTIL_NIL_STMT_ 317290001Sglebius#define EVTHREAD_COND_WAIT(cond, lock) EVUTIL_NIL_STMT_ 318290001Sglebius#define EVTHREAD_COND_WAIT_TIMED(cond, lock, howlong) EVUTIL_NIL_STMT_ 319290001Sglebius 320290001Sglebius#define EVTHREAD_LOCKING_ENABLED() 0 321290001Sglebius 322290001Sglebius#endif 323290001Sglebius 324290001Sglebius/* This code is shared between both lock impls */ 325290001Sglebius#if ! defined(EVENT__DISABLE_THREAD_SUPPORT) 326290001Sglebius/** Helper: put lockvar1 and lockvar2 into pointerwise ascending order. */ 327290001Sglebius#define EVLOCK_SORTLOCKS_(lockvar1, lockvar2) \ 328290001Sglebius do { \ 329290001Sglebius if (lockvar1 && lockvar2 && lockvar1 > lockvar2) { \ 330290001Sglebius void *tmp = lockvar1; \ 331290001Sglebius lockvar1 = lockvar2; \ 332290001Sglebius lockvar2 = tmp; \ 333290001Sglebius } \ 334290001Sglebius } while (0) 335290001Sglebius 336290001Sglebius/** Acquire both lock1 and lock2. Always allocates locks in the same order, 337290001Sglebius * so that two threads locking two locks with LOCK2 will not deadlock. */ 338290001Sglebius#define EVLOCK_LOCK2(lock1,lock2,mode1,mode2) \ 339290001Sglebius do { \ 340290001Sglebius void *lock1_tmplock_ = (lock1); \ 341290001Sglebius void *lock2_tmplock_ = (lock2); \ 342290001Sglebius EVLOCK_SORTLOCKS_(lock1_tmplock_,lock2_tmplock_); \ 343290001Sglebius EVLOCK_LOCK(lock1_tmplock_,mode1); \ 344290001Sglebius if (lock2_tmplock_ != lock1_tmplock_) \ 345290001Sglebius EVLOCK_LOCK(lock2_tmplock_,mode2); \ 346290001Sglebius } while (0) 347290001Sglebius/** Release both lock1 and lock2. */ 348290001Sglebius#define EVLOCK_UNLOCK2(lock1,lock2,mode1,mode2) \ 349290001Sglebius do { \ 350290001Sglebius void *lock1_tmplock_ = (lock1); \ 351290001Sglebius void *lock2_tmplock_ = (lock2); \ 352290001Sglebius EVLOCK_SORTLOCKS_(lock1_tmplock_,lock2_tmplock_); \ 353290001Sglebius if (lock2_tmplock_ != lock1_tmplock_) \ 354290001Sglebius EVLOCK_UNLOCK(lock2_tmplock_,mode2); \ 355290001Sglebius EVLOCK_UNLOCK(lock1_tmplock_,mode1); \ 356290001Sglebius } while (0) 357290001Sglebius 358290001Sglebiusint evthread_is_debug_lock_held_(void *lock); 359290001Sglebiusvoid *evthread_debug_get_real_lock_(void *lock); 360290001Sglebius 361290001Sglebiusvoid *evthread_setup_global_lock_(void *lock_, unsigned locktype, 362290001Sglebius int enable_locks); 363290001Sglebius 364290001Sglebius#define EVTHREAD_SETUP_GLOBAL_LOCK(lockvar, locktype) \ 365290001Sglebius do { \ 366290001Sglebius lockvar = evthread_setup_global_lock_(lockvar, \ 367290001Sglebius (locktype), enable_locks); \ 368290001Sglebius if (!lockvar) { \ 369290001Sglebius event_warn("Couldn't allocate %s", #lockvar); \ 370290001Sglebius return -1; \ 371290001Sglebius } \ 372290001Sglebius } while (0); 373290001Sglebius 374290001Sglebiusint event_global_setup_locks_(const int enable_locks); 375290001Sglebiusint evsig_global_setup_locks_(const int enable_locks); 376290001Sglebiusint evutil_global_setup_locks_(const int enable_locks); 377290001Sglebiusint evutil_secure_rng_global_setup_locks_(const int enable_locks); 378290001Sglebius 379290001Sglebius/** Return current evthread_lock_callbacks */ 380290001Sglebiusstruct evthread_lock_callbacks *evthread_get_lock_callbacks(void); 381290001Sglebius/** Return current evthread_condition_callbacks */ 382290001Sglebiusstruct evthread_condition_callbacks *evthread_get_condition_callbacks(void); 383290001Sglebius/** Disable locking for internal usage (like global shutdown) */ 384290001Sglebiusvoid evthreadimpl_disable_lock_debugging_(void); 385290001Sglebius 386290001Sglebius#endif 387290001Sglebius 388290001Sglebius#ifdef __cplusplus 389290001Sglebius} 390290001Sglebius#endif 391290001Sglebius 392290001Sglebius#endif /* EVTHREAD_INTERNAL_H_INCLUDED_ */ 393