xref: /netbsd-src/external/bsd/ntp/dist/sntp/libevent/evthread.c (revision eabc0478de71e4e011a5b4e0392741e01d491794)
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