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
27290001Sglebius#include "event2/event-config.h"
28290001Sglebius#include "evconfig-private.h"
29290001Sglebius
30290001Sglebius#ifndef EVENT__DISABLE_THREAD_SUPPORT
31290001Sglebius
32290001Sglebius#include "event2/thread.h"
33290001Sglebius
34290001Sglebius#include <stdlib.h>
35290001Sglebius#include <string.h>
36290001Sglebius
37290001Sglebius#include "log-internal.h"
38290001Sglebius#include "mm-internal.h"
39290001Sglebius#include "util-internal.h"
40290001Sglebius#include "evthread-internal.h"
41290001Sglebius
42290001Sglebius#ifdef EVTHREAD_EXPOSE_STRUCTS
43290001Sglebius#define GLOBAL
44290001Sglebius#else
45290001Sglebius#define GLOBAL static
46290001Sglebius#endif
47290001Sglebius
48290001Sglebius/* globals */
49290001SglebiusGLOBAL int evthread_lock_debugging_enabled_ = 0;
50290001SglebiusGLOBAL struct evthread_lock_callbacks evthread_lock_fns_ = {
51290001Sglebius	0, 0, NULL, NULL, NULL, NULL
52290001Sglebius};
53290001SglebiusGLOBAL unsigned long (*evthread_id_fn_)(void) = NULL;
54290001SglebiusGLOBAL struct evthread_condition_callbacks evthread_cond_fns_ = {
55290001Sglebius	0, NULL, NULL, NULL, NULL
56290001Sglebius};
57290001Sglebius
58290001Sglebius/* Used for debugging */
59290001Sglebiusstatic struct evthread_lock_callbacks original_lock_fns_ = {
60290001Sglebius	0, 0, NULL, NULL, NULL, NULL
61290001Sglebius};
62290001Sglebiusstatic struct evthread_condition_callbacks original_cond_fns_ = {
63290001Sglebius	0, NULL, NULL, NULL, NULL
64290001Sglebius};
65290001Sglebius
66290001Sglebiusvoid
67290001Sglebiusevthread_set_id_callback(unsigned long (*id_fn)(void))
68290001Sglebius{
69290001Sglebius	evthread_id_fn_ = id_fn;
70290001Sglebius}
71290001Sglebius
72290001Sglebiusstruct evthread_lock_callbacks *evthread_get_lock_callbacks()
73290001Sglebius{
74290001Sglebius	return evthread_lock_debugging_enabled_
75290001Sglebius	    ? &original_lock_fns_ : &evthread_lock_fns_;
76290001Sglebius}
77290001Sglebiusstruct evthread_condition_callbacks *evthread_get_condition_callbacks()
78290001Sglebius{
79290001Sglebius	return evthread_lock_debugging_enabled_
80290001Sglebius	    ? &original_cond_fns_ : &evthread_cond_fns_;
81290001Sglebius}
82290001Sglebiusvoid evthreadimpl_disable_lock_debugging_(void)
83290001Sglebius{
84290001Sglebius	evthread_lock_debugging_enabled_ = 0;
85290001Sglebius}
86290001Sglebius
87290001Sglebiusint
88290001Sglebiusevthread_set_lock_callbacks(const struct evthread_lock_callbacks *cbs)
89290001Sglebius{
90290001Sglebius	struct evthread_lock_callbacks *target = evthread_get_lock_callbacks();
91290001Sglebius
92290001Sglebius	if (!cbs) {
93290001Sglebius		if (target->alloc)
94290001Sglebius			event_warnx("Trying to disable lock functions after "
95290001Sglebius			    "they have been set up will probaby not work.");
96290001Sglebius		memset(target, 0, sizeof(evthread_lock_fns_));
97290001Sglebius		return 0;
98290001Sglebius	}
99290001Sglebius	if (target->alloc) {
100290001Sglebius		/* Uh oh; we already had locking callbacks set up.*/
101290001Sglebius		if (target->lock_api_version == cbs->lock_api_version &&
102290001Sglebius			target->supported_locktypes == cbs->supported_locktypes &&
103290001Sglebius			target->alloc == cbs->alloc &&
104290001Sglebius			target->free == cbs->free &&
105290001Sglebius			target->lock == cbs->lock &&
106290001Sglebius			target->unlock == cbs->unlock) {
107290001Sglebius			/* no change -- allow this. */
108290001Sglebius			return 0;
109290001Sglebius		}
110290001Sglebius		event_warnx("Can't change lock callbacks once they have been "
111290001Sglebius		    "initialized.");
112290001Sglebius		return -1;
113290001Sglebius	}
114290001Sglebius	if (cbs->alloc && cbs->free && cbs->lock && cbs->unlock) {
115290001Sglebius		memcpy(target, cbs, sizeof(evthread_lock_fns_));
116290001Sglebius		return event_global_setup_locks_(1);
117290001Sglebius	} else {
118290001Sglebius		return -1;
119290001Sglebius	}
120290001Sglebius}
121290001Sglebius
122290001Sglebiusint
123290001Sglebiusevthread_set_condition_callbacks(const struct evthread_condition_callbacks *cbs)
124290001Sglebius{
125290001Sglebius	struct evthread_condition_callbacks *target = evthread_get_condition_callbacks();
126290001Sglebius
127290001Sglebius	if (!cbs) {
128290001Sglebius		if (target->alloc_condition)
129290001Sglebius			event_warnx("Trying to disable condition functions "
130290001Sglebius			    "after they have been set up will probaby not "
131290001Sglebius			    "work.");
132290001Sglebius		memset(target, 0, sizeof(evthread_cond_fns_));
133290001Sglebius		return 0;
134290001Sglebius	}
135290001Sglebius	if (target->alloc_condition) {
136290001Sglebius		/* Uh oh; we already had condition callbacks set up.*/
137290001Sglebius		if (target->condition_api_version == cbs->condition_api_version &&
138290001Sglebius			target->alloc_condition == cbs->alloc_condition &&
139290001Sglebius			target->free_condition == cbs->free_condition &&
140290001Sglebius			target->signal_condition == cbs->signal_condition &&
141290001Sglebius			target->wait_condition == cbs->wait_condition) {
142290001Sglebius			/* no change -- allow this. */
143290001Sglebius			return 0;
144290001Sglebius		}
145290001Sglebius		event_warnx("Can't change condition callbacks once they "
146290001Sglebius		    "have been initialized.");
147290001Sglebius		return -1;
148290001Sglebius	}
149290001Sglebius	if (cbs->alloc_condition && cbs->free_condition &&
150290001Sglebius	    cbs->signal_condition && cbs->wait_condition) {
151290001Sglebius		memcpy(target, cbs, sizeof(evthread_cond_fns_));
152290001Sglebius	}
153290001Sglebius	if (evthread_lock_debugging_enabled_) {
154290001Sglebius		evthread_cond_fns_.alloc_condition = cbs->alloc_condition;
155290001Sglebius		evthread_cond_fns_.free_condition = cbs->free_condition;
156290001Sglebius		evthread_cond_fns_.signal_condition = cbs->signal_condition;
157290001Sglebius	}
158290001Sglebius	return 0;
159290001Sglebius}
160290001Sglebius
161290001Sglebius#define DEBUG_LOCK_SIG	0xdeb0b10c
162290001Sglebius
163290001Sglebiusstruct debug_lock {
164290001Sglebius	unsigned signature;
165290001Sglebius	unsigned locktype;
166290001Sglebius	unsigned long held_by;
167290001Sglebius	/* XXXX if we ever use read-write locks, we will need a separate
168290001Sglebius	 * lock to protect count. */
169290001Sglebius	int count;
170290001Sglebius	void *lock;
171290001Sglebius};
172290001Sglebius
173290001Sglebiusstatic void *
174290001Sglebiusdebug_lock_alloc(unsigned locktype)
175290001Sglebius{
176290001Sglebius	struct debug_lock *result = mm_malloc(sizeof(struct debug_lock));
177290001Sglebius	if (!result)
178290001Sglebius		return NULL;
179290001Sglebius	if (original_lock_fns_.alloc) {
180290001Sglebius		if (!(result->lock = original_lock_fns_.alloc(
181290001Sglebius				locktype|EVTHREAD_LOCKTYPE_RECURSIVE))) {
182290001Sglebius			mm_free(result);
183290001Sglebius			return NULL;
184290001Sglebius		}
185290001Sglebius	} else {
186290001Sglebius		result->lock = NULL;
187290001Sglebius	}
188290001Sglebius	result->signature = DEBUG_LOCK_SIG;
189290001Sglebius	result->locktype = locktype;
190290001Sglebius	result->count = 0;
191290001Sglebius	result->held_by = 0;
192290001Sglebius	return result;
193290001Sglebius}
194290001Sglebius
195290001Sglebiusstatic void
196290001Sglebiusdebug_lock_free(void *lock_, unsigned locktype)
197290001Sglebius{
198290001Sglebius	struct debug_lock *lock = lock_;
199290001Sglebius	EVUTIL_ASSERT(lock->count == 0);
200290001Sglebius	EVUTIL_ASSERT(locktype == lock->locktype);
201290001Sglebius	EVUTIL_ASSERT(DEBUG_LOCK_SIG == lock->signature);
202290001Sglebius	if (original_lock_fns_.free) {
203290001Sglebius		original_lock_fns_.free(lock->lock,
204290001Sglebius		    lock->locktype|EVTHREAD_LOCKTYPE_RECURSIVE);
205290001Sglebius	}
206290001Sglebius	lock->lock = NULL;
207290001Sglebius	lock->count = -100;
208290001Sglebius	lock->signature = 0x12300fda;
209290001Sglebius	mm_free(lock);
210290001Sglebius}
211290001Sglebius
212290001Sglebiusstatic void
213290001Sglebiusevthread_debug_lock_mark_locked(unsigned mode, struct debug_lock *lock)
214290001Sglebius{
215290001Sglebius	EVUTIL_ASSERT(DEBUG_LOCK_SIG == lock->signature);
216290001Sglebius	++lock->count;
217290001Sglebius	if (!(lock->locktype & EVTHREAD_LOCKTYPE_RECURSIVE))
218290001Sglebius		EVUTIL_ASSERT(lock->count == 1);
219290001Sglebius	if (evthread_id_fn_) {
220290001Sglebius		unsigned long me;
221290001Sglebius		me = evthread_id_fn_();
222290001Sglebius		if (lock->count > 1)
223290001Sglebius			EVUTIL_ASSERT(lock->held_by == me);
224290001Sglebius		lock->held_by = me;
225290001Sglebius	}
226290001Sglebius}
227290001Sglebius
228290001Sglebiusstatic int
229290001Sglebiusdebug_lock_lock(unsigned mode, void *lock_)
230290001Sglebius{
231290001Sglebius	struct debug_lock *lock = lock_;
232290001Sglebius	int res = 0;
233290001Sglebius	if (lock->locktype & EVTHREAD_LOCKTYPE_READWRITE)
234290001Sglebius		EVUTIL_ASSERT(mode & (EVTHREAD_READ|EVTHREAD_WRITE));
235290001Sglebius	else
236290001Sglebius		EVUTIL_ASSERT((mode & (EVTHREAD_READ|EVTHREAD_WRITE)) == 0);
237290001Sglebius	if (original_lock_fns_.lock)
238290001Sglebius		res = original_lock_fns_.lock(mode, lock->lock);
239290001Sglebius	if (!res) {
240290001Sglebius		evthread_debug_lock_mark_locked(mode, lock);
241290001Sglebius	}
242290001Sglebius	return res;
243290001Sglebius}
244290001Sglebius
245290001Sglebiusstatic void
246290001Sglebiusevthread_debug_lock_mark_unlocked(unsigned mode, struct debug_lock *lock)
247290001Sglebius{
248290001Sglebius	EVUTIL_ASSERT(DEBUG_LOCK_SIG == lock->signature);
249290001Sglebius	if (lock->locktype & EVTHREAD_LOCKTYPE_READWRITE)
250290001Sglebius		EVUTIL_ASSERT(mode & (EVTHREAD_READ|EVTHREAD_WRITE));
251290001Sglebius	else
252290001Sglebius		EVUTIL_ASSERT((mode & (EVTHREAD_READ|EVTHREAD_WRITE)) == 0);
253290001Sglebius	if (evthread_id_fn_) {
254290001Sglebius		unsigned long me;
255290001Sglebius		me = evthread_id_fn_();
256290001Sglebius		EVUTIL_ASSERT(lock->held_by == me);
257290001Sglebius		if (lock->count == 1)
258290001Sglebius			lock->held_by = 0;
259290001Sglebius	}
260290001Sglebius	--lock->count;
261290001Sglebius	EVUTIL_ASSERT(lock->count >= 0);
262290001Sglebius}
263290001Sglebius
264290001Sglebiusstatic int
265290001Sglebiusdebug_lock_unlock(unsigned mode, void *lock_)
266290001Sglebius{
267290001Sglebius	struct debug_lock *lock = lock_;
268290001Sglebius	int res = 0;
269290001Sglebius	evthread_debug_lock_mark_unlocked(mode, lock);
270290001Sglebius	if (original_lock_fns_.unlock)
271290001Sglebius		res = original_lock_fns_.unlock(mode, lock->lock);
272290001Sglebius	return res;
273290001Sglebius}
274290001Sglebius
275290001Sglebiusstatic int
276290001Sglebiusdebug_cond_wait(void *cond_, void *lock_, const struct timeval *tv)
277290001Sglebius{
278290001Sglebius	int r;
279290001Sglebius	struct debug_lock *lock = lock_;
280290001Sglebius	EVUTIL_ASSERT(lock);
281290001Sglebius	EVUTIL_ASSERT(DEBUG_LOCK_SIG == lock->signature);
282290001Sglebius	EVLOCK_ASSERT_LOCKED(lock_);
283290001Sglebius	evthread_debug_lock_mark_unlocked(0, lock);
284290001Sglebius	r = original_cond_fns_.wait_condition(cond_, lock->lock, tv);
285290001Sglebius	evthread_debug_lock_mark_locked(0, lock);
286290001Sglebius	return r;
287290001Sglebius}
288290001Sglebius
289290001Sglebius/* misspelled version for backward compatibility */
290290001Sglebiusvoid
291290001Sglebiusevthread_enable_lock_debuging(void)
292290001Sglebius{
293290001Sglebius	evthread_enable_lock_debugging();
294290001Sglebius}
295290001Sglebius
296290001Sglebiusvoid
297290001Sglebiusevthread_enable_lock_debugging(void)
298290001Sglebius{
299290001Sglebius	struct evthread_lock_callbacks cbs = {
300290001Sglebius		EVTHREAD_LOCK_API_VERSION,
301290001Sglebius		EVTHREAD_LOCKTYPE_RECURSIVE,
302290001Sglebius		debug_lock_alloc,
303290001Sglebius		debug_lock_free,
304290001Sglebius		debug_lock_lock,
305290001Sglebius		debug_lock_unlock
306290001Sglebius	};
307290001Sglebius	if (evthread_lock_debugging_enabled_)
308290001Sglebius		return;
309290001Sglebius	memcpy(&original_lock_fns_, &evthread_lock_fns_,
310290001Sglebius	    sizeof(struct evthread_lock_callbacks));
311290001Sglebius	memcpy(&evthread_lock_fns_, &cbs,
312290001Sglebius	    sizeof(struct evthread_lock_callbacks));
313290001Sglebius
314290001Sglebius	memcpy(&original_cond_fns_, &evthread_cond_fns_,
315290001Sglebius	    sizeof(struct evthread_condition_callbacks));
316290001Sglebius	evthread_cond_fns_.wait_condition = debug_cond_wait;
317290001Sglebius	evthread_lock_debugging_enabled_ = 1;
318290001Sglebius
319290001Sglebius	/* XXX return value should get checked. */
320290001Sglebius	event_global_setup_locks_(0);
321290001Sglebius}
322290001Sglebius
323290001Sglebiusint
324290001Sglebiusevthread_is_debug_lock_held_(void *lock_)
325290001Sglebius{
326290001Sglebius	struct debug_lock *lock = lock_;
327290001Sglebius	if (! lock->count)
328290001Sglebius		return 0;
329290001Sglebius	if (evthread_id_fn_) {
330290001Sglebius		unsigned long me = evthread_id_fn_();
331290001Sglebius		if (lock->held_by != me)
332290001Sglebius			return 0;
333290001Sglebius	}
334290001Sglebius	return 1;
335290001Sglebius}
336290001Sglebius
337290001Sglebiusvoid *
338290001Sglebiusevthread_debug_get_real_lock_(void *lock_)
339290001Sglebius{
340290001Sglebius	struct debug_lock *lock = lock_;
341290001Sglebius	return lock->lock;
342290001Sglebius}
343290001Sglebius
344290001Sglebiusvoid *
345290001Sglebiusevthread_setup_global_lock_(void *lock_, unsigned locktype, int enable_locks)
346290001Sglebius{
347290001Sglebius	/* there are four cases here:
348290001Sglebius	   1) we're turning on debugging; locking is not on.
349290001Sglebius	   2) we're turning on debugging; locking is on.
350290001Sglebius	   3) we're turning on locking; debugging is not on.
351290001Sglebius	   4) we're turning on locking; debugging is on. */
352290001Sglebius
353290001Sglebius	if (!enable_locks && original_lock_fns_.alloc == NULL) {
354290001Sglebius		/* Case 1: allocate a debug lock. */
355290001Sglebius		EVUTIL_ASSERT(lock_ == NULL);
356290001Sglebius		return debug_lock_alloc(locktype);
357290001Sglebius	} else if (!enable_locks && original_lock_fns_.alloc != NULL) {
358290001Sglebius		/* Case 2: wrap the lock in a debug lock. */
359290001Sglebius		struct debug_lock *lock;
360290001Sglebius		EVUTIL_ASSERT(lock_ != NULL);
361290001Sglebius
362290001Sglebius		if (!(locktype & EVTHREAD_LOCKTYPE_RECURSIVE)) {
363290001Sglebius			/* We can't wrap it: We need a recursive lock */
364290001Sglebius			original_lock_fns_.free(lock_, locktype);
365290001Sglebius			return debug_lock_alloc(locktype);
366290001Sglebius		}
367290001Sglebius		lock = mm_malloc(sizeof(struct debug_lock));
368290001Sglebius		if (!lock) {
369290001Sglebius			original_lock_fns_.free(lock_, locktype);
370290001Sglebius			return NULL;
371290001Sglebius		}
372290001Sglebius		lock->lock = lock_;
373290001Sglebius		lock->locktype = locktype;
374290001Sglebius		lock->count = 0;
375290001Sglebius		lock->held_by = 0;
376290001Sglebius		return lock;
377290001Sglebius	} else if (enable_locks && ! evthread_lock_debugging_enabled_) {
378290001Sglebius		/* Case 3: allocate a regular lock */
379290001Sglebius		EVUTIL_ASSERT(lock_ == NULL);
380290001Sglebius		return evthread_lock_fns_.alloc(locktype);
381290001Sglebius	} else {
382290001Sglebius		/* Case 4: Fill in a debug lock with a real lock */
383290001Sglebius		struct debug_lock *lock = lock_;
384290001Sglebius		EVUTIL_ASSERT(enable_locks &&
385290001Sglebius		              evthread_lock_debugging_enabled_);
386290001Sglebius		EVUTIL_ASSERT(lock->locktype == locktype);
387290001Sglebius		EVUTIL_ASSERT(lock->lock == NULL);
388290001Sglebius		lock->lock = original_lock_fns_.alloc(
389290001Sglebius			locktype|EVTHREAD_LOCKTYPE_RECURSIVE);
390290001Sglebius		if (!lock->lock) {
391290001Sglebius			lock->count = -200;
392290001Sglebius			mm_free(lock);
393290001Sglebius			return NULL;
394290001Sglebius		}
395290001Sglebius		return lock;
396290001Sglebius	}
397290001Sglebius}
398290001Sglebius
399290001Sglebius
400290001Sglebius#ifndef EVTHREAD_EXPOSE_STRUCTS
401290001Sglebiusunsigned long
402290001Sglebiusevthreadimpl_get_id_()
403290001Sglebius{
404290001Sglebius	return evthread_id_fn_ ? evthread_id_fn_() : 1;
405290001Sglebius}
406290001Sglebiusvoid *
407290001Sglebiusevthreadimpl_lock_alloc_(unsigned locktype)
408290001Sglebius{
409290001Sglebius	return evthread_lock_fns_.alloc ?
410290001Sglebius	    evthread_lock_fns_.alloc(locktype) : NULL;
411290001Sglebius}
412290001Sglebiusvoid
413290001Sglebiusevthreadimpl_lock_free_(void *lock, unsigned locktype)
414290001Sglebius{
415290001Sglebius	if (evthread_lock_fns_.free)
416290001Sglebius		evthread_lock_fns_.free(lock, locktype);
417290001Sglebius}
418290001Sglebiusint
419290001Sglebiusevthreadimpl_lock_lock_(unsigned mode, void *lock)
420290001Sglebius{
421290001Sglebius	if (evthread_lock_fns_.lock)
422290001Sglebius		return evthread_lock_fns_.lock(mode, lock);
423290001Sglebius	else
424290001Sglebius		return 0;
425290001Sglebius}
426290001Sglebiusint
427290001Sglebiusevthreadimpl_lock_unlock_(unsigned mode, void *lock)
428290001Sglebius{
429290001Sglebius	if (evthread_lock_fns_.unlock)
430290001Sglebius		return evthread_lock_fns_.unlock(mode, lock);
431290001Sglebius	else
432290001Sglebius		return 0;
433290001Sglebius}
434290001Sglebiusvoid *
435290001Sglebiusevthreadimpl_cond_alloc_(unsigned condtype)
436290001Sglebius{
437290001Sglebius	return evthread_cond_fns_.alloc_condition ?
438290001Sglebius	    evthread_cond_fns_.alloc_condition(condtype) : NULL;
439290001Sglebius}
440290001Sglebiusvoid
441290001Sglebiusevthreadimpl_cond_free_(void *cond)
442290001Sglebius{
443290001Sglebius	if (evthread_cond_fns_.free_condition)
444290001Sglebius		evthread_cond_fns_.free_condition(cond);
445290001Sglebius}
446290001Sglebiusint
447290001Sglebiusevthreadimpl_cond_signal_(void *cond, int broadcast)
448290001Sglebius{
449290001Sglebius	if (evthread_cond_fns_.signal_condition)
450290001Sglebius		return evthread_cond_fns_.signal_condition(cond, broadcast);
451290001Sglebius	else
452290001Sglebius		return 0;
453290001Sglebius}
454290001Sglebiusint
455290001Sglebiusevthreadimpl_cond_wait_(void *cond, void *lock, const struct timeval *tv)
456290001Sglebius{
457290001Sglebius	if (evthread_cond_fns_.wait_condition)
458290001Sglebius		return evthread_cond_fns_.wait_condition(cond, lock, tv);
459290001Sglebius	else
460290001Sglebius		return 0;
461290001Sglebius}
462290001Sglebiusint
463290001Sglebiusevthreadimpl_is_lock_debugging_enabled_(void)
464290001Sglebius{
465290001Sglebius	return evthread_lock_debugging_enabled_;
466290001Sglebius}
467290001Sglebius
468290001Sglebiusint
469290001Sglebiusevthreadimpl_locking_enabled_(void)
470290001Sglebius{
471290001Sglebius	return evthread_lock_fns_.lock != NULL;
472290001Sglebius}
473290001Sglebius#endif
474290001Sglebius
475290001Sglebius#endif
476