1*eabc0478Schristos /* $NetBSD: evthread.c,v 1.7 2024/08/18 20:47:21 christos Exp $ */ 28585484eSchristos 38585484eSchristos /* 48585484eSchristos * Copyright (c) 2008-2012 Niels Provos, Nick Mathewson 58585484eSchristos * 68585484eSchristos * Redistribution and use in source and binary forms, with or without 78585484eSchristos * modification, are permitted provided that the following conditions 88585484eSchristos * are met: 98585484eSchristos * 1. Redistributions of source code must retain the above copyright 108585484eSchristos * notice, this list of conditions and the following disclaimer. 118585484eSchristos * 2. Redistributions in binary form must reproduce the above copyright 128585484eSchristos * notice, this list of conditions and the following disclaimer in the 138585484eSchristos * documentation and/or other materials provided with the distribution. 148585484eSchristos * 3. The name of the author may not be used to endorse or promote products 158585484eSchristos * derived from this software without specific prior written permission. 168585484eSchristos * 178585484eSchristos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 188585484eSchristos * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 198585484eSchristos * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 208585484eSchristos * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 218585484eSchristos * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 228585484eSchristos * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 238585484eSchristos * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 248585484eSchristos * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 258585484eSchristos * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 268585484eSchristos * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 278585484eSchristos */ 288585484eSchristos 298585484eSchristos #include "event2/event-config.h" 308585484eSchristos #include "evconfig-private.h" 318585484eSchristos 328585484eSchristos #ifndef EVENT__DISABLE_THREAD_SUPPORT 338585484eSchristos 348585484eSchristos #include "event2/thread.h" 358585484eSchristos 368585484eSchristos #include <stdlib.h> 378585484eSchristos #include <string.h> 388585484eSchristos 398585484eSchristos #include "log-internal.h" 408585484eSchristos #include "mm-internal.h" 418585484eSchristos #include "util-internal.h" 428585484eSchristos #include "evthread-internal.h" 438585484eSchristos 448585484eSchristos #ifdef EVTHREAD_EXPOSE_STRUCTS 458585484eSchristos #define GLOBAL 468585484eSchristos #else 478585484eSchristos #define GLOBAL static 488585484eSchristos #endif 498585484eSchristos 50*eabc0478Schristos #ifndef EVENT__DISABLE_DEBUG_MODE 51*eabc0478Schristos extern int event_debug_created_threadable_ctx_; 52*eabc0478Schristos extern int event_debug_mode_on_; 53*eabc0478Schristos #endif 54*eabc0478Schristos 558585484eSchristos /* globals */ 568585484eSchristos GLOBAL int evthread_lock_debugging_enabled_ = 0; 578585484eSchristos GLOBAL struct evthread_lock_callbacks evthread_lock_fns_ = { 588585484eSchristos 0, 0, NULL, NULL, NULL, NULL 598585484eSchristos }; 608585484eSchristos GLOBAL unsigned long (*evthread_id_fn_)(void) = NULL; 618585484eSchristos GLOBAL struct evthread_condition_callbacks evthread_cond_fns_ = { 628585484eSchristos 0, NULL, NULL, NULL, NULL 638585484eSchristos }; 648585484eSchristos 658585484eSchristos /* Used for debugging */ 668585484eSchristos static struct evthread_lock_callbacks original_lock_fns_ = { 678585484eSchristos 0, 0, NULL, NULL, NULL, NULL 688585484eSchristos }; 698585484eSchristos static struct evthread_condition_callbacks original_cond_fns_ = { 708585484eSchristos 0, NULL, NULL, NULL, NULL 718585484eSchristos }; 728585484eSchristos 738585484eSchristos void 748585484eSchristos evthread_set_id_callback(unsigned long (*id_fn)(void)) 758585484eSchristos { 768585484eSchristos evthread_id_fn_ = id_fn; 778585484eSchristos } 788585484eSchristos 797476e6e4Schristos struct evthread_lock_callbacks *evthread_get_lock_callbacks() 807476e6e4Schristos { 817476e6e4Schristos return evthread_lock_debugging_enabled_ 827476e6e4Schristos ? &original_lock_fns_ : &evthread_lock_fns_; 837476e6e4Schristos } 847476e6e4Schristos struct evthread_condition_callbacks *evthread_get_condition_callbacks() 857476e6e4Schristos { 867476e6e4Schristos return evthread_lock_debugging_enabled_ 877476e6e4Schristos ? &original_cond_fns_ : &evthread_cond_fns_; 887476e6e4Schristos } 897476e6e4Schristos void evthreadimpl_disable_lock_debugging_(void) 907476e6e4Schristos { 917476e6e4Schristos evthread_lock_debugging_enabled_ = 0; 927476e6e4Schristos } 937476e6e4Schristos 948585484eSchristos int 958585484eSchristos evthread_set_lock_callbacks(const struct evthread_lock_callbacks *cbs) 968585484eSchristos { 977476e6e4Schristos struct evthread_lock_callbacks *target = evthread_get_lock_callbacks(); 988585484eSchristos 99*eabc0478Schristos #ifndef EVENT__DISABLE_DEBUG_MODE 100*eabc0478Schristos if (event_debug_mode_on_) { 101*eabc0478Schristos if (event_debug_created_threadable_ctx_) { 102*eabc0478Schristos event_errx(1, "evthread initialization must be called BEFORE anything else!"); 103*eabc0478Schristos } 104*eabc0478Schristos } 105*eabc0478Schristos #endif 106*eabc0478Schristos 1078585484eSchristos if (!cbs) { 1088585484eSchristos if (target->alloc) 1098585484eSchristos event_warnx("Trying to disable lock functions after " 1108585484eSchristos "they have been set up will probaby not work."); 1118585484eSchristos memset(target, 0, sizeof(evthread_lock_fns_)); 1128585484eSchristos return 0; 1138585484eSchristos } 1148585484eSchristos if (target->alloc) { 1158585484eSchristos /* Uh oh; we already had locking callbacks set up.*/ 1168585484eSchristos if (target->lock_api_version == cbs->lock_api_version && 1178585484eSchristos target->supported_locktypes == cbs->supported_locktypes && 1188585484eSchristos target->alloc == cbs->alloc && 1198585484eSchristos target->free == cbs->free && 1208585484eSchristos target->lock == cbs->lock && 1218585484eSchristos target->unlock == cbs->unlock) { 1228585484eSchristos /* no change -- allow this. */ 1238585484eSchristos return 0; 1248585484eSchristos } 1258585484eSchristos event_warnx("Can't change lock callbacks once they have been " 1268585484eSchristos "initialized."); 1278585484eSchristos return -1; 1288585484eSchristos } 1298585484eSchristos if (cbs->alloc && cbs->free && cbs->lock && cbs->unlock) { 1308585484eSchristos memcpy(target, cbs, sizeof(evthread_lock_fns_)); 1318585484eSchristos return event_global_setup_locks_(1); 1328585484eSchristos } else { 1338585484eSchristos return -1; 1348585484eSchristos } 1358585484eSchristos } 1368585484eSchristos 1378585484eSchristos int 1388585484eSchristos evthread_set_condition_callbacks(const struct evthread_condition_callbacks *cbs) 1398585484eSchristos { 1407476e6e4Schristos struct evthread_condition_callbacks *target = evthread_get_condition_callbacks(); 1418585484eSchristos 142*eabc0478Schristos #ifndef EVENT__DISABLE_DEBUG_MODE 143*eabc0478Schristos if (event_debug_mode_on_) { 144*eabc0478Schristos if (event_debug_created_threadable_ctx_) { 145*eabc0478Schristos event_errx(1, "evthread initialization must be called BEFORE anything else!"); 146*eabc0478Schristos } 147*eabc0478Schristos } 148*eabc0478Schristos #endif 149*eabc0478Schristos 1508585484eSchristos if (!cbs) { 1518585484eSchristos if (target->alloc_condition) 1528585484eSchristos event_warnx("Trying to disable condition functions " 1538585484eSchristos "after they have been set up will probaby not " 1548585484eSchristos "work."); 1558585484eSchristos memset(target, 0, sizeof(evthread_cond_fns_)); 1568585484eSchristos return 0; 1578585484eSchristos } 1588585484eSchristos if (target->alloc_condition) { 1598585484eSchristos /* Uh oh; we already had condition callbacks set up.*/ 1608585484eSchristos if (target->condition_api_version == cbs->condition_api_version && 1618585484eSchristos target->alloc_condition == cbs->alloc_condition && 1628585484eSchristos target->free_condition == cbs->free_condition && 1638585484eSchristos target->signal_condition == cbs->signal_condition && 1648585484eSchristos target->wait_condition == cbs->wait_condition) { 1658585484eSchristos /* no change -- allow this. */ 1668585484eSchristos return 0; 1678585484eSchristos } 1688585484eSchristos event_warnx("Can't change condition callbacks once they " 1698585484eSchristos "have been initialized."); 1708585484eSchristos return -1; 1718585484eSchristos } 1728585484eSchristos if (cbs->alloc_condition && cbs->free_condition && 1738585484eSchristos cbs->signal_condition && cbs->wait_condition) { 1748585484eSchristos memcpy(target, cbs, sizeof(evthread_cond_fns_)); 1758585484eSchristos } 1768585484eSchristos if (evthread_lock_debugging_enabled_) { 1778585484eSchristos evthread_cond_fns_.alloc_condition = cbs->alloc_condition; 1788585484eSchristos evthread_cond_fns_.free_condition = cbs->free_condition; 1798585484eSchristos evthread_cond_fns_.signal_condition = cbs->signal_condition; 1808585484eSchristos } 1818585484eSchristos return 0; 1828585484eSchristos } 1838585484eSchristos 1848585484eSchristos #define DEBUG_LOCK_SIG 0xdeb0b10c 1858585484eSchristos 1868585484eSchristos struct debug_lock { 1878585484eSchristos unsigned signature; 1888585484eSchristos unsigned locktype; 1898585484eSchristos unsigned long held_by; 1908585484eSchristos /* XXXX if we ever use read-write locks, we will need a separate 1918585484eSchristos * lock to protect count. */ 1928585484eSchristos int count; 1938585484eSchristos void *lock; 1948585484eSchristos }; 1958585484eSchristos 1968585484eSchristos static void * 1978585484eSchristos debug_lock_alloc(unsigned locktype) 1988585484eSchristos { 1998585484eSchristos struct debug_lock *result = mm_malloc(sizeof(struct debug_lock)); 2008585484eSchristos if (!result) 2018585484eSchristos return NULL; 2028585484eSchristos if (original_lock_fns_.alloc) { 2038585484eSchristos if (!(result->lock = original_lock_fns_.alloc( 2048585484eSchristos locktype|EVTHREAD_LOCKTYPE_RECURSIVE))) { 2058585484eSchristos mm_free(result); 2068585484eSchristos return NULL; 2078585484eSchristos } 2088585484eSchristos } else { 2098585484eSchristos result->lock = NULL; 2108585484eSchristos } 2118585484eSchristos result->signature = DEBUG_LOCK_SIG; 2128585484eSchristos result->locktype = locktype; 2138585484eSchristos result->count = 0; 2148585484eSchristos result->held_by = 0; 2158585484eSchristos return result; 2168585484eSchristos } 2178585484eSchristos 2188585484eSchristos static void 2198585484eSchristos debug_lock_free(void *lock_, unsigned locktype) 2208585484eSchristos { 2218585484eSchristos struct debug_lock *lock = lock_; 2228585484eSchristos EVUTIL_ASSERT(lock->count == 0); 2238585484eSchristos EVUTIL_ASSERT(locktype == lock->locktype); 2248585484eSchristos EVUTIL_ASSERT(DEBUG_LOCK_SIG == lock->signature); 2258585484eSchristos if (original_lock_fns_.free) { 2268585484eSchristos original_lock_fns_.free(lock->lock, 2278585484eSchristos lock->locktype|EVTHREAD_LOCKTYPE_RECURSIVE); 2288585484eSchristos } 2298585484eSchristos lock->lock = NULL; 2308585484eSchristos lock->count = -100; 2318585484eSchristos lock->signature = 0x12300fda; 2328585484eSchristos mm_free(lock); 2338585484eSchristos } 2348585484eSchristos 2358585484eSchristos static void 2368585484eSchristos evthread_debug_lock_mark_locked(unsigned mode, struct debug_lock *lock) 2378585484eSchristos { 2388585484eSchristos EVUTIL_ASSERT(DEBUG_LOCK_SIG == lock->signature); 2398585484eSchristos ++lock->count; 2408585484eSchristos if (!(lock->locktype & EVTHREAD_LOCKTYPE_RECURSIVE)) 2418585484eSchristos EVUTIL_ASSERT(lock->count == 1); 2428585484eSchristos if (evthread_id_fn_) { 2438585484eSchristos unsigned long me; 2448585484eSchristos me = evthread_id_fn_(); 2458585484eSchristos if (lock->count > 1) 2468585484eSchristos EVUTIL_ASSERT(lock->held_by == me); 2478585484eSchristos lock->held_by = me; 2488585484eSchristos } 2498585484eSchristos } 2508585484eSchristos 2518585484eSchristos static int 2528585484eSchristos debug_lock_lock(unsigned mode, void *lock_) 2538585484eSchristos { 2548585484eSchristos struct debug_lock *lock = lock_; 2558585484eSchristos int res = 0; 2568585484eSchristos if (lock->locktype & EVTHREAD_LOCKTYPE_READWRITE) 2578585484eSchristos EVUTIL_ASSERT(mode & (EVTHREAD_READ|EVTHREAD_WRITE)); 2588585484eSchristos else 2598585484eSchristos EVUTIL_ASSERT((mode & (EVTHREAD_READ|EVTHREAD_WRITE)) == 0); 2608585484eSchristos if (original_lock_fns_.lock) 2618585484eSchristos res = original_lock_fns_.lock(mode, lock->lock); 2628585484eSchristos if (!res) { 2638585484eSchristos evthread_debug_lock_mark_locked(mode, lock); 2648585484eSchristos } 2658585484eSchristos return res; 2668585484eSchristos } 2678585484eSchristos 2688585484eSchristos static void 2698585484eSchristos evthread_debug_lock_mark_unlocked(unsigned mode, struct debug_lock *lock) 2708585484eSchristos { 2718585484eSchristos EVUTIL_ASSERT(DEBUG_LOCK_SIG == lock->signature); 2728585484eSchristos if (lock->locktype & EVTHREAD_LOCKTYPE_READWRITE) 2738585484eSchristos EVUTIL_ASSERT(mode & (EVTHREAD_READ|EVTHREAD_WRITE)); 2748585484eSchristos else 2758585484eSchristos EVUTIL_ASSERT((mode & (EVTHREAD_READ|EVTHREAD_WRITE)) == 0); 2768585484eSchristos if (evthread_id_fn_) { 2778585484eSchristos unsigned long me; 2788585484eSchristos me = evthread_id_fn_(); 2798585484eSchristos EVUTIL_ASSERT(lock->held_by == me); 2808585484eSchristos if (lock->count == 1) 2818585484eSchristos lock->held_by = 0; 2828585484eSchristos } 2838585484eSchristos --lock->count; 2848585484eSchristos EVUTIL_ASSERT(lock->count >= 0); 2858585484eSchristos } 2868585484eSchristos 2878585484eSchristos static int 2888585484eSchristos debug_lock_unlock(unsigned mode, void *lock_) 2898585484eSchristos { 2908585484eSchristos struct debug_lock *lock = lock_; 2918585484eSchristos int res = 0; 2928585484eSchristos evthread_debug_lock_mark_unlocked(mode, lock); 2938585484eSchristos if (original_lock_fns_.unlock) 2948585484eSchristos res = original_lock_fns_.unlock(mode, lock->lock); 2958585484eSchristos return res; 2968585484eSchristos } 2978585484eSchristos 2988585484eSchristos static int 2998585484eSchristos debug_cond_wait(void *cond_, void *lock_, const struct timeval *tv) 3008585484eSchristos { 3018585484eSchristos int r; 3028585484eSchristos struct debug_lock *lock = lock_; 3038585484eSchristos EVUTIL_ASSERT(lock); 3048585484eSchristos EVUTIL_ASSERT(DEBUG_LOCK_SIG == lock->signature); 3058585484eSchristos EVLOCK_ASSERT_LOCKED(lock_); 3068585484eSchristos evthread_debug_lock_mark_unlocked(0, lock); 3078585484eSchristos r = original_cond_fns_.wait_condition(cond_, lock->lock, tv); 3088585484eSchristos evthread_debug_lock_mark_locked(0, lock); 3098585484eSchristos return r; 3108585484eSchristos } 3118585484eSchristos 3128585484eSchristos /* misspelled version for backward compatibility */ 3138585484eSchristos void 3148585484eSchristos evthread_enable_lock_debuging(void) 3158585484eSchristos { 3168585484eSchristos evthread_enable_lock_debugging(); 3178585484eSchristos } 3188585484eSchristos 3198585484eSchristos void 3208585484eSchristos evthread_enable_lock_debugging(void) 3218585484eSchristos { 3228585484eSchristos struct evthread_lock_callbacks cbs = { 3238585484eSchristos EVTHREAD_LOCK_API_VERSION, 3248585484eSchristos EVTHREAD_LOCKTYPE_RECURSIVE, 3258585484eSchristos debug_lock_alloc, 3268585484eSchristos debug_lock_free, 3278585484eSchristos debug_lock_lock, 3288585484eSchristos debug_lock_unlock 3298585484eSchristos }; 3308585484eSchristos if (evthread_lock_debugging_enabled_) 3318585484eSchristos return; 3328585484eSchristos memcpy(&original_lock_fns_, &evthread_lock_fns_, 3338585484eSchristos sizeof(struct evthread_lock_callbacks)); 3348585484eSchristos memcpy(&evthread_lock_fns_, &cbs, 3358585484eSchristos sizeof(struct evthread_lock_callbacks)); 3368585484eSchristos 3378585484eSchristos memcpy(&original_cond_fns_, &evthread_cond_fns_, 3388585484eSchristos sizeof(struct evthread_condition_callbacks)); 3398585484eSchristos evthread_cond_fns_.wait_condition = debug_cond_wait; 3408585484eSchristos evthread_lock_debugging_enabled_ = 1; 3418585484eSchristos 3428585484eSchristos /* XXX return value should get checked. */ 3438585484eSchristos event_global_setup_locks_(0); 3448585484eSchristos } 3458585484eSchristos 3468585484eSchristos int 3478585484eSchristos evthread_is_debug_lock_held_(void *lock_) 3488585484eSchristos { 3498585484eSchristos struct debug_lock *lock = lock_; 3508585484eSchristos if (! lock->count) 3518585484eSchristos return 0; 3528585484eSchristos if (evthread_id_fn_) { 3538585484eSchristos unsigned long me = evthread_id_fn_(); 3548585484eSchristos if (lock->held_by != me) 3558585484eSchristos return 0; 3568585484eSchristos } 3578585484eSchristos return 1; 3588585484eSchristos } 3598585484eSchristos 3608585484eSchristos void * 3618585484eSchristos evthread_debug_get_real_lock_(void *lock_) 3628585484eSchristos { 3638585484eSchristos struct debug_lock *lock = lock_; 3648585484eSchristos return lock->lock; 3658585484eSchristos } 3668585484eSchristos 3678585484eSchristos void * 3688585484eSchristos evthread_setup_global_lock_(void *lock_, unsigned locktype, int enable_locks) 3698585484eSchristos { 3708585484eSchristos /* there are four cases here: 3718585484eSchristos 1) we're turning on debugging; locking is not on. 3728585484eSchristos 2) we're turning on debugging; locking is on. 3738585484eSchristos 3) we're turning on locking; debugging is not on. 3748585484eSchristos 4) we're turning on locking; debugging is on. */ 3758585484eSchristos 3768585484eSchristos if (!enable_locks && original_lock_fns_.alloc == NULL) { 3778585484eSchristos /* Case 1: allocate a debug lock. */ 3788585484eSchristos EVUTIL_ASSERT(lock_ == NULL); 3798585484eSchristos return debug_lock_alloc(locktype); 3808585484eSchristos } else if (!enable_locks && original_lock_fns_.alloc != NULL) { 3818585484eSchristos /* Case 2: wrap the lock in a debug lock. */ 3828585484eSchristos struct debug_lock *lock; 3838585484eSchristos EVUTIL_ASSERT(lock_ != NULL); 3848585484eSchristos 3858585484eSchristos if (!(locktype & EVTHREAD_LOCKTYPE_RECURSIVE)) { 3868585484eSchristos /* We can't wrap it: We need a recursive lock */ 3878585484eSchristos original_lock_fns_.free(lock_, locktype); 3888585484eSchristos return debug_lock_alloc(locktype); 3898585484eSchristos } 3908585484eSchristos lock = mm_malloc(sizeof(struct debug_lock)); 3918585484eSchristos if (!lock) { 3928585484eSchristos original_lock_fns_.free(lock_, locktype); 3938585484eSchristos return NULL; 3948585484eSchristos } 3958585484eSchristos lock->lock = lock_; 3968585484eSchristos lock->locktype = locktype; 3978585484eSchristos lock->count = 0; 3988585484eSchristos lock->held_by = 0; 3998585484eSchristos return lock; 4008585484eSchristos } else if (enable_locks && ! evthread_lock_debugging_enabled_) { 4018585484eSchristos /* Case 3: allocate a regular lock */ 4028585484eSchristos EVUTIL_ASSERT(lock_ == NULL); 4038585484eSchristos return evthread_lock_fns_.alloc(locktype); 4048585484eSchristos } else { 4058585484eSchristos /* Case 4: Fill in a debug lock with a real lock */ 406*eabc0478Schristos struct debug_lock *lock = lock_ ? lock_ : debug_lock_alloc(locktype); 4078585484eSchristos EVUTIL_ASSERT(enable_locks && 4088585484eSchristos evthread_lock_debugging_enabled_); 4098585484eSchristos EVUTIL_ASSERT(lock->locktype == locktype); 410*eabc0478Schristos if (!lock->lock) { 4118585484eSchristos lock->lock = original_lock_fns_.alloc( 4128585484eSchristos locktype|EVTHREAD_LOCKTYPE_RECURSIVE); 4138585484eSchristos if (!lock->lock) { 4148585484eSchristos lock->count = -200; 4158585484eSchristos mm_free(lock); 4168585484eSchristos return NULL; 4178585484eSchristos } 418*eabc0478Schristos } 4198585484eSchristos return lock; 4208585484eSchristos } 4218585484eSchristos } 4228585484eSchristos 4238585484eSchristos 4248585484eSchristos #ifndef EVTHREAD_EXPOSE_STRUCTS 4258585484eSchristos unsigned long 4268585484eSchristos evthreadimpl_get_id_() 4278585484eSchristos { 4288585484eSchristos return evthread_id_fn_ ? evthread_id_fn_() : 1; 4298585484eSchristos } 4308585484eSchristos void * 4318585484eSchristos evthreadimpl_lock_alloc_(unsigned locktype) 4328585484eSchristos { 433*eabc0478Schristos #ifndef EVENT__DISABLE_DEBUG_MODE 434*eabc0478Schristos if (event_debug_mode_on_) { 435*eabc0478Schristos event_debug_created_threadable_ctx_ = 1; 436*eabc0478Schristos } 437*eabc0478Schristos #endif 438*eabc0478Schristos 4398585484eSchristos return evthread_lock_fns_.alloc ? 4408585484eSchristos evthread_lock_fns_.alloc(locktype) : NULL; 4418585484eSchristos } 4428585484eSchristos void 4438585484eSchristos evthreadimpl_lock_free_(void *lock, unsigned locktype) 4448585484eSchristos { 4458585484eSchristos if (evthread_lock_fns_.free) 4468585484eSchristos evthread_lock_fns_.free(lock, locktype); 4478585484eSchristos } 4488585484eSchristos int 4498585484eSchristos evthreadimpl_lock_lock_(unsigned mode, void *lock) 4508585484eSchristos { 4518585484eSchristos if (evthread_lock_fns_.lock) 4528585484eSchristos return evthread_lock_fns_.lock(mode, lock); 4538585484eSchristos else 4548585484eSchristos return 0; 4558585484eSchristos } 4568585484eSchristos int 4578585484eSchristos evthreadimpl_lock_unlock_(unsigned mode, void *lock) 4588585484eSchristos { 4598585484eSchristos if (evthread_lock_fns_.unlock) 4608585484eSchristos return evthread_lock_fns_.unlock(mode, lock); 4618585484eSchristos else 4628585484eSchristos return 0; 4638585484eSchristos } 4648585484eSchristos void * 4658585484eSchristos evthreadimpl_cond_alloc_(unsigned condtype) 4668585484eSchristos { 467*eabc0478Schristos #ifndef EVENT__DISABLE_DEBUG_MODE 468*eabc0478Schristos if (event_debug_mode_on_) { 469*eabc0478Schristos event_debug_created_threadable_ctx_ = 1; 470*eabc0478Schristos } 471*eabc0478Schristos #endif 472*eabc0478Schristos 4738585484eSchristos return evthread_cond_fns_.alloc_condition ? 4748585484eSchristos evthread_cond_fns_.alloc_condition(condtype) : NULL; 4758585484eSchristos } 4768585484eSchristos void 4778585484eSchristos evthreadimpl_cond_free_(void *cond) 4788585484eSchristos { 4798585484eSchristos if (evthread_cond_fns_.free_condition) 4808585484eSchristos evthread_cond_fns_.free_condition(cond); 4818585484eSchristos } 4828585484eSchristos int 4838585484eSchristos evthreadimpl_cond_signal_(void *cond, int broadcast) 4848585484eSchristos { 4858585484eSchristos if (evthread_cond_fns_.signal_condition) 4868585484eSchristos return evthread_cond_fns_.signal_condition(cond, broadcast); 4878585484eSchristos else 4888585484eSchristos return 0; 4898585484eSchristos } 4908585484eSchristos int 4918585484eSchristos evthreadimpl_cond_wait_(void *cond, void *lock, const struct timeval *tv) 4928585484eSchristos { 4938585484eSchristos if (evthread_cond_fns_.wait_condition) 4948585484eSchristos return evthread_cond_fns_.wait_condition(cond, lock, tv); 4958585484eSchristos else 4968585484eSchristos return 0; 4978585484eSchristos } 4988585484eSchristos int 4998585484eSchristos evthreadimpl_is_lock_debugging_enabled_(void) 5008585484eSchristos { 5018585484eSchristos return evthread_lock_debugging_enabled_; 5028585484eSchristos } 5038585484eSchristos 5048585484eSchristos int 5058585484eSchristos evthreadimpl_locking_enabled_(void) 5068585484eSchristos { 5078585484eSchristos return evthread_lock_fns_.lock != NULL; 5088585484eSchristos } 5098585484eSchristos #endif 5108585484eSchristos 5118585484eSchristos #endif 512