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