12b15cb3dSCy Schubert /*
22b15cb3dSCy Schubert * Copyright (c) 2008-2012 Niels Provos, Nick Mathewson
32b15cb3dSCy Schubert *
42b15cb3dSCy Schubert * Redistribution and use in source and binary forms, with or without
52b15cb3dSCy Schubert * modification, are permitted provided that the following conditions
62b15cb3dSCy Schubert * are met:
72b15cb3dSCy Schubert * 1. Redistributions of source code must retain the above copyright
82b15cb3dSCy Schubert * notice, this list of conditions and the following disclaimer.
92b15cb3dSCy Schubert * 2. Redistributions in binary form must reproduce the above copyright
102b15cb3dSCy Schubert * notice, this list of conditions and the following disclaimer in the
112b15cb3dSCy Schubert * documentation and/or other materials provided with the distribution.
122b15cb3dSCy Schubert * 3. The name of the author may not be used to endorse or promote products
132b15cb3dSCy Schubert * derived from this software without specific prior written permission.
142b15cb3dSCy Schubert *
152b15cb3dSCy Schubert * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
162b15cb3dSCy Schubert * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
172b15cb3dSCy Schubert * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
182b15cb3dSCy Schubert * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
192b15cb3dSCy Schubert * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
202b15cb3dSCy Schubert * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
212b15cb3dSCy Schubert * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
222b15cb3dSCy Schubert * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
232b15cb3dSCy Schubert * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
242b15cb3dSCy Schubert * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
252b15cb3dSCy Schubert */
262b15cb3dSCy Schubert
272b15cb3dSCy Schubert #include "event2/event-config.h"
282b15cb3dSCy Schubert #include "evconfig-private.h"
292b15cb3dSCy Schubert
302b15cb3dSCy Schubert #ifndef EVENT__DISABLE_THREAD_SUPPORT
312b15cb3dSCy Schubert
322b15cb3dSCy Schubert #include "event2/thread.h"
332b15cb3dSCy Schubert
342b15cb3dSCy Schubert #include <stdlib.h>
352b15cb3dSCy Schubert #include <string.h>
362b15cb3dSCy Schubert
372b15cb3dSCy Schubert #include "log-internal.h"
382b15cb3dSCy Schubert #include "mm-internal.h"
392b15cb3dSCy Schubert #include "util-internal.h"
402b15cb3dSCy Schubert #include "evthread-internal.h"
412b15cb3dSCy Schubert
422b15cb3dSCy Schubert #ifdef EVTHREAD_EXPOSE_STRUCTS
432b15cb3dSCy Schubert #define GLOBAL
442b15cb3dSCy Schubert #else
452b15cb3dSCy Schubert #define GLOBAL static
462b15cb3dSCy Schubert #endif
472b15cb3dSCy Schubert
48*a466cc55SCy Schubert #ifndef EVENT__DISABLE_DEBUG_MODE
49*a466cc55SCy Schubert extern int event_debug_created_threadable_ctx_;
50*a466cc55SCy Schubert extern int event_debug_mode_on_;
51*a466cc55SCy Schubert #endif
52*a466cc55SCy Schubert
532b15cb3dSCy Schubert /* globals */
542b15cb3dSCy Schubert GLOBAL int evthread_lock_debugging_enabled_ = 0;
552b15cb3dSCy Schubert GLOBAL struct evthread_lock_callbacks evthread_lock_fns_ = {
562b15cb3dSCy Schubert 0, 0, NULL, NULL, NULL, NULL
572b15cb3dSCy Schubert };
582b15cb3dSCy Schubert GLOBAL unsigned long (*evthread_id_fn_)(void) = NULL;
592b15cb3dSCy Schubert GLOBAL struct evthread_condition_callbacks evthread_cond_fns_ = {
602b15cb3dSCy Schubert 0, NULL, NULL, NULL, NULL
612b15cb3dSCy Schubert };
622b15cb3dSCy Schubert
632b15cb3dSCy Schubert /* Used for debugging */
642b15cb3dSCy Schubert static struct evthread_lock_callbacks original_lock_fns_ = {
652b15cb3dSCy Schubert 0, 0, NULL, NULL, NULL, NULL
662b15cb3dSCy Schubert };
672b15cb3dSCy Schubert static struct evthread_condition_callbacks original_cond_fns_ = {
682b15cb3dSCy Schubert 0, NULL, NULL, NULL, NULL
692b15cb3dSCy Schubert };
702b15cb3dSCy Schubert
712b15cb3dSCy Schubert void
evthread_set_id_callback(unsigned long (* id_fn)(void))722b15cb3dSCy Schubert evthread_set_id_callback(unsigned long (*id_fn)(void))
732b15cb3dSCy Schubert {
742b15cb3dSCy Schubert evthread_id_fn_ = id_fn;
752b15cb3dSCy Schubert }
762b15cb3dSCy Schubert
evthread_get_lock_callbacks()77a25439b6SCy Schubert struct evthread_lock_callbacks *evthread_get_lock_callbacks()
78a25439b6SCy Schubert {
79a25439b6SCy Schubert return evthread_lock_debugging_enabled_
80a25439b6SCy Schubert ? &original_lock_fns_ : &evthread_lock_fns_;
81a25439b6SCy Schubert }
evthread_get_condition_callbacks()82a25439b6SCy Schubert struct evthread_condition_callbacks *evthread_get_condition_callbacks()
83a25439b6SCy Schubert {
84a25439b6SCy Schubert return evthread_lock_debugging_enabled_
85a25439b6SCy Schubert ? &original_cond_fns_ : &evthread_cond_fns_;
86a25439b6SCy Schubert }
evthreadimpl_disable_lock_debugging_(void)87a25439b6SCy Schubert void evthreadimpl_disable_lock_debugging_(void)
88a25439b6SCy Schubert {
89a25439b6SCy Schubert evthread_lock_debugging_enabled_ = 0;
90a25439b6SCy Schubert }
91a25439b6SCy Schubert
922b15cb3dSCy Schubert int
evthread_set_lock_callbacks(const struct evthread_lock_callbacks * cbs)932b15cb3dSCy Schubert evthread_set_lock_callbacks(const struct evthread_lock_callbacks *cbs)
942b15cb3dSCy Schubert {
95a25439b6SCy Schubert struct evthread_lock_callbacks *target = evthread_get_lock_callbacks();
962b15cb3dSCy Schubert
97*a466cc55SCy Schubert #ifndef EVENT__DISABLE_DEBUG_MODE
98*a466cc55SCy Schubert if (event_debug_mode_on_) {
99*a466cc55SCy Schubert if (event_debug_created_threadable_ctx_) {
100*a466cc55SCy Schubert event_errx(1, "evthread initialization must be called BEFORE anything else!");
101*a466cc55SCy Schubert }
102*a466cc55SCy Schubert }
103*a466cc55SCy Schubert #endif
104*a466cc55SCy Schubert
1052b15cb3dSCy Schubert if (!cbs) {
1062b15cb3dSCy Schubert if (target->alloc)
1072b15cb3dSCy Schubert event_warnx("Trying to disable lock functions after "
1082b15cb3dSCy Schubert "they have been set up will probaby not work.");
1092b15cb3dSCy Schubert memset(target, 0, sizeof(evthread_lock_fns_));
1102b15cb3dSCy Schubert return 0;
1112b15cb3dSCy Schubert }
1122b15cb3dSCy Schubert if (target->alloc) {
1132b15cb3dSCy Schubert /* Uh oh; we already had locking callbacks set up.*/
1142b15cb3dSCy Schubert if (target->lock_api_version == cbs->lock_api_version &&
1152b15cb3dSCy Schubert target->supported_locktypes == cbs->supported_locktypes &&
1162b15cb3dSCy Schubert target->alloc == cbs->alloc &&
1172b15cb3dSCy Schubert target->free == cbs->free &&
1182b15cb3dSCy Schubert target->lock == cbs->lock &&
1192b15cb3dSCy Schubert target->unlock == cbs->unlock) {
1202b15cb3dSCy Schubert /* no change -- allow this. */
1212b15cb3dSCy Schubert return 0;
1222b15cb3dSCy Schubert }
1232b15cb3dSCy Schubert event_warnx("Can't change lock callbacks once they have been "
1242b15cb3dSCy Schubert "initialized.");
1252b15cb3dSCy Schubert return -1;
1262b15cb3dSCy Schubert }
1272b15cb3dSCy Schubert if (cbs->alloc && cbs->free && cbs->lock && cbs->unlock) {
1282b15cb3dSCy Schubert memcpy(target, cbs, sizeof(evthread_lock_fns_));
1292b15cb3dSCy Schubert return event_global_setup_locks_(1);
1302b15cb3dSCy Schubert } else {
1312b15cb3dSCy Schubert return -1;
1322b15cb3dSCy Schubert }
1332b15cb3dSCy Schubert }
1342b15cb3dSCy Schubert
1352b15cb3dSCy Schubert int
evthread_set_condition_callbacks(const struct evthread_condition_callbacks * cbs)1362b15cb3dSCy Schubert evthread_set_condition_callbacks(const struct evthread_condition_callbacks *cbs)
1372b15cb3dSCy Schubert {
138a25439b6SCy Schubert struct evthread_condition_callbacks *target = evthread_get_condition_callbacks();
1392b15cb3dSCy Schubert
140*a466cc55SCy Schubert #ifndef EVENT__DISABLE_DEBUG_MODE
141*a466cc55SCy Schubert if (event_debug_mode_on_) {
142*a466cc55SCy Schubert if (event_debug_created_threadable_ctx_) {
143*a466cc55SCy Schubert event_errx(1, "evthread initialization must be called BEFORE anything else!");
144*a466cc55SCy Schubert }
145*a466cc55SCy Schubert }
146*a466cc55SCy Schubert #endif
147*a466cc55SCy Schubert
1482b15cb3dSCy Schubert if (!cbs) {
1492b15cb3dSCy Schubert if (target->alloc_condition)
1502b15cb3dSCy Schubert event_warnx("Trying to disable condition functions "
1512b15cb3dSCy Schubert "after they have been set up will probaby not "
1522b15cb3dSCy Schubert "work.");
1532b15cb3dSCy Schubert memset(target, 0, sizeof(evthread_cond_fns_));
1542b15cb3dSCy Schubert return 0;
1552b15cb3dSCy Schubert }
1562b15cb3dSCy Schubert if (target->alloc_condition) {
1572b15cb3dSCy Schubert /* Uh oh; we already had condition callbacks set up.*/
1582b15cb3dSCy Schubert if (target->condition_api_version == cbs->condition_api_version &&
1592b15cb3dSCy Schubert target->alloc_condition == cbs->alloc_condition &&
1602b15cb3dSCy Schubert target->free_condition == cbs->free_condition &&
1612b15cb3dSCy Schubert target->signal_condition == cbs->signal_condition &&
1622b15cb3dSCy Schubert target->wait_condition == cbs->wait_condition) {
1632b15cb3dSCy Schubert /* no change -- allow this. */
1642b15cb3dSCy Schubert return 0;
1652b15cb3dSCy Schubert }
1662b15cb3dSCy Schubert event_warnx("Can't change condition callbacks once they "
1672b15cb3dSCy Schubert "have been initialized.");
1682b15cb3dSCy Schubert return -1;
1692b15cb3dSCy Schubert }
1702b15cb3dSCy Schubert if (cbs->alloc_condition && cbs->free_condition &&
1712b15cb3dSCy Schubert cbs->signal_condition && cbs->wait_condition) {
1722b15cb3dSCy Schubert memcpy(target, cbs, sizeof(evthread_cond_fns_));
1732b15cb3dSCy Schubert }
1742b15cb3dSCy Schubert if (evthread_lock_debugging_enabled_) {
1752b15cb3dSCy Schubert evthread_cond_fns_.alloc_condition = cbs->alloc_condition;
1762b15cb3dSCy Schubert evthread_cond_fns_.free_condition = cbs->free_condition;
1772b15cb3dSCy Schubert evthread_cond_fns_.signal_condition = cbs->signal_condition;
1782b15cb3dSCy Schubert }
1792b15cb3dSCy Schubert return 0;
1802b15cb3dSCy Schubert }
1812b15cb3dSCy Schubert
1822b15cb3dSCy Schubert #define DEBUG_LOCK_SIG 0xdeb0b10c
1832b15cb3dSCy Schubert
1842b15cb3dSCy Schubert struct debug_lock {
1852b15cb3dSCy Schubert unsigned signature;
1862b15cb3dSCy Schubert unsigned locktype;
1872b15cb3dSCy Schubert unsigned long held_by;
1882b15cb3dSCy Schubert /* XXXX if we ever use read-write locks, we will need a separate
1892b15cb3dSCy Schubert * lock to protect count. */
1902b15cb3dSCy Schubert int count;
1912b15cb3dSCy Schubert void *lock;
1922b15cb3dSCy Schubert };
1932b15cb3dSCy Schubert
1942b15cb3dSCy Schubert static void *
debug_lock_alloc(unsigned locktype)1952b15cb3dSCy Schubert debug_lock_alloc(unsigned locktype)
1962b15cb3dSCy Schubert {
1972b15cb3dSCy Schubert struct debug_lock *result = mm_malloc(sizeof(struct debug_lock));
1982b15cb3dSCy Schubert if (!result)
1992b15cb3dSCy Schubert return NULL;
2002b15cb3dSCy Schubert if (original_lock_fns_.alloc) {
2012b15cb3dSCy Schubert if (!(result->lock = original_lock_fns_.alloc(
2022b15cb3dSCy Schubert locktype|EVTHREAD_LOCKTYPE_RECURSIVE))) {
2032b15cb3dSCy Schubert mm_free(result);
2042b15cb3dSCy Schubert return NULL;
2052b15cb3dSCy Schubert }
2062b15cb3dSCy Schubert } else {
2072b15cb3dSCy Schubert result->lock = NULL;
2082b15cb3dSCy Schubert }
2092b15cb3dSCy Schubert result->signature = DEBUG_LOCK_SIG;
2102b15cb3dSCy Schubert result->locktype = locktype;
2112b15cb3dSCy Schubert result->count = 0;
2122b15cb3dSCy Schubert result->held_by = 0;
2132b15cb3dSCy Schubert return result;
2142b15cb3dSCy Schubert }
2152b15cb3dSCy Schubert
2162b15cb3dSCy Schubert static void
debug_lock_free(void * lock_,unsigned locktype)2172b15cb3dSCy Schubert debug_lock_free(void *lock_, unsigned locktype)
2182b15cb3dSCy Schubert {
2192b15cb3dSCy Schubert struct debug_lock *lock = lock_;
2202b15cb3dSCy Schubert EVUTIL_ASSERT(lock->count == 0);
2212b15cb3dSCy Schubert EVUTIL_ASSERT(locktype == lock->locktype);
2222b15cb3dSCy Schubert EVUTIL_ASSERT(DEBUG_LOCK_SIG == lock->signature);
2232b15cb3dSCy Schubert if (original_lock_fns_.free) {
2242b15cb3dSCy Schubert original_lock_fns_.free(lock->lock,
2252b15cb3dSCy Schubert lock->locktype|EVTHREAD_LOCKTYPE_RECURSIVE);
2262b15cb3dSCy Schubert }
2272b15cb3dSCy Schubert lock->lock = NULL;
2282b15cb3dSCy Schubert lock->count = -100;
2292b15cb3dSCy Schubert lock->signature = 0x12300fda;
2302b15cb3dSCy Schubert mm_free(lock);
2312b15cb3dSCy Schubert }
2322b15cb3dSCy Schubert
2332b15cb3dSCy Schubert static void
evthread_debug_lock_mark_locked(unsigned mode,struct debug_lock * lock)2342b15cb3dSCy Schubert evthread_debug_lock_mark_locked(unsigned mode, struct debug_lock *lock)
2352b15cb3dSCy Schubert {
2362b15cb3dSCy Schubert EVUTIL_ASSERT(DEBUG_LOCK_SIG == lock->signature);
2372b15cb3dSCy Schubert ++lock->count;
2382b15cb3dSCy Schubert if (!(lock->locktype & EVTHREAD_LOCKTYPE_RECURSIVE))
2392b15cb3dSCy Schubert EVUTIL_ASSERT(lock->count == 1);
2402b15cb3dSCy Schubert if (evthread_id_fn_) {
2412b15cb3dSCy Schubert unsigned long me;
2422b15cb3dSCy Schubert me = evthread_id_fn_();
2432b15cb3dSCy Schubert if (lock->count > 1)
2442b15cb3dSCy Schubert EVUTIL_ASSERT(lock->held_by == me);
2452b15cb3dSCy Schubert lock->held_by = me;
2462b15cb3dSCy Schubert }
2472b15cb3dSCy Schubert }
2482b15cb3dSCy Schubert
2492b15cb3dSCy Schubert static int
debug_lock_lock(unsigned mode,void * lock_)2502b15cb3dSCy Schubert debug_lock_lock(unsigned mode, void *lock_)
2512b15cb3dSCy Schubert {
2522b15cb3dSCy Schubert struct debug_lock *lock = lock_;
2532b15cb3dSCy Schubert int res = 0;
2542b15cb3dSCy Schubert if (lock->locktype & EVTHREAD_LOCKTYPE_READWRITE)
2552b15cb3dSCy Schubert EVUTIL_ASSERT(mode & (EVTHREAD_READ|EVTHREAD_WRITE));
2562b15cb3dSCy Schubert else
2572b15cb3dSCy Schubert EVUTIL_ASSERT((mode & (EVTHREAD_READ|EVTHREAD_WRITE)) == 0);
2582b15cb3dSCy Schubert if (original_lock_fns_.lock)
2592b15cb3dSCy Schubert res = original_lock_fns_.lock(mode, lock->lock);
2602b15cb3dSCy Schubert if (!res) {
2612b15cb3dSCy Schubert evthread_debug_lock_mark_locked(mode, lock);
2622b15cb3dSCy Schubert }
2632b15cb3dSCy Schubert return res;
2642b15cb3dSCy Schubert }
2652b15cb3dSCy Schubert
2662b15cb3dSCy Schubert static void
evthread_debug_lock_mark_unlocked(unsigned mode,struct debug_lock * lock)2672b15cb3dSCy Schubert evthread_debug_lock_mark_unlocked(unsigned mode, struct debug_lock *lock)
2682b15cb3dSCy Schubert {
2692b15cb3dSCy Schubert EVUTIL_ASSERT(DEBUG_LOCK_SIG == lock->signature);
2702b15cb3dSCy Schubert if (lock->locktype & EVTHREAD_LOCKTYPE_READWRITE)
2712b15cb3dSCy Schubert EVUTIL_ASSERT(mode & (EVTHREAD_READ|EVTHREAD_WRITE));
2722b15cb3dSCy Schubert else
2732b15cb3dSCy Schubert EVUTIL_ASSERT((mode & (EVTHREAD_READ|EVTHREAD_WRITE)) == 0);
2742b15cb3dSCy Schubert if (evthread_id_fn_) {
2752b15cb3dSCy Schubert unsigned long me;
2762b15cb3dSCy Schubert me = evthread_id_fn_();
2772b15cb3dSCy Schubert EVUTIL_ASSERT(lock->held_by == me);
2782b15cb3dSCy Schubert if (lock->count == 1)
2792b15cb3dSCy Schubert lock->held_by = 0;
2802b15cb3dSCy Schubert }
2812b15cb3dSCy Schubert --lock->count;
2822b15cb3dSCy Schubert EVUTIL_ASSERT(lock->count >= 0);
2832b15cb3dSCy Schubert }
2842b15cb3dSCy Schubert
2852b15cb3dSCy Schubert static int
debug_lock_unlock(unsigned mode,void * lock_)2862b15cb3dSCy Schubert debug_lock_unlock(unsigned mode, void *lock_)
2872b15cb3dSCy Schubert {
2882b15cb3dSCy Schubert struct debug_lock *lock = lock_;
2892b15cb3dSCy Schubert int res = 0;
2902b15cb3dSCy Schubert evthread_debug_lock_mark_unlocked(mode, lock);
2912b15cb3dSCy Schubert if (original_lock_fns_.unlock)
2922b15cb3dSCy Schubert res = original_lock_fns_.unlock(mode, lock->lock);
2932b15cb3dSCy Schubert return res;
2942b15cb3dSCy Schubert }
2952b15cb3dSCy Schubert
2962b15cb3dSCy Schubert static int
debug_cond_wait(void * cond_,void * lock_,const struct timeval * tv)2972b15cb3dSCy Schubert debug_cond_wait(void *cond_, void *lock_, const struct timeval *tv)
2982b15cb3dSCy Schubert {
2992b15cb3dSCy Schubert int r;
3002b15cb3dSCy Schubert struct debug_lock *lock = lock_;
3012b15cb3dSCy Schubert EVUTIL_ASSERT(lock);
3022b15cb3dSCy Schubert EVUTIL_ASSERT(DEBUG_LOCK_SIG == lock->signature);
3032b15cb3dSCy Schubert EVLOCK_ASSERT_LOCKED(lock_);
3042b15cb3dSCy Schubert evthread_debug_lock_mark_unlocked(0, lock);
3052b15cb3dSCy Schubert r = original_cond_fns_.wait_condition(cond_, lock->lock, tv);
3062b15cb3dSCy Schubert evthread_debug_lock_mark_locked(0, lock);
3072b15cb3dSCy Schubert return r;
3082b15cb3dSCy Schubert }
3092b15cb3dSCy Schubert
3102b15cb3dSCy Schubert /* misspelled version for backward compatibility */
3112b15cb3dSCy Schubert void
evthread_enable_lock_debuging(void)3122b15cb3dSCy Schubert evthread_enable_lock_debuging(void)
3132b15cb3dSCy Schubert {
3142b15cb3dSCy Schubert evthread_enable_lock_debugging();
3152b15cb3dSCy Schubert }
3162b15cb3dSCy Schubert
3172b15cb3dSCy Schubert void
evthread_enable_lock_debugging(void)3182b15cb3dSCy Schubert evthread_enable_lock_debugging(void)
3192b15cb3dSCy Schubert {
3202b15cb3dSCy Schubert struct evthread_lock_callbacks cbs = {
3212b15cb3dSCy Schubert EVTHREAD_LOCK_API_VERSION,
3222b15cb3dSCy Schubert EVTHREAD_LOCKTYPE_RECURSIVE,
3232b15cb3dSCy Schubert debug_lock_alloc,
3242b15cb3dSCy Schubert debug_lock_free,
3252b15cb3dSCy Schubert debug_lock_lock,
3262b15cb3dSCy Schubert debug_lock_unlock
3272b15cb3dSCy Schubert };
3282b15cb3dSCy Schubert if (evthread_lock_debugging_enabled_)
3292b15cb3dSCy Schubert return;
3302b15cb3dSCy Schubert memcpy(&original_lock_fns_, &evthread_lock_fns_,
3312b15cb3dSCy Schubert sizeof(struct evthread_lock_callbacks));
3322b15cb3dSCy Schubert memcpy(&evthread_lock_fns_, &cbs,
3332b15cb3dSCy Schubert sizeof(struct evthread_lock_callbacks));
3342b15cb3dSCy Schubert
3352b15cb3dSCy Schubert memcpy(&original_cond_fns_, &evthread_cond_fns_,
3362b15cb3dSCy Schubert sizeof(struct evthread_condition_callbacks));
3372b15cb3dSCy Schubert evthread_cond_fns_.wait_condition = debug_cond_wait;
3382b15cb3dSCy Schubert evthread_lock_debugging_enabled_ = 1;
3392b15cb3dSCy Schubert
3402b15cb3dSCy Schubert /* XXX return value should get checked. */
3412b15cb3dSCy Schubert event_global_setup_locks_(0);
3422b15cb3dSCy Schubert }
3432b15cb3dSCy Schubert
3442b15cb3dSCy Schubert int
evthread_is_debug_lock_held_(void * lock_)3452b15cb3dSCy Schubert evthread_is_debug_lock_held_(void *lock_)
3462b15cb3dSCy Schubert {
3472b15cb3dSCy Schubert struct debug_lock *lock = lock_;
3482b15cb3dSCy Schubert if (! lock->count)
3492b15cb3dSCy Schubert return 0;
3502b15cb3dSCy Schubert if (evthread_id_fn_) {
3512b15cb3dSCy Schubert unsigned long me = evthread_id_fn_();
3522b15cb3dSCy Schubert if (lock->held_by != me)
3532b15cb3dSCy Schubert return 0;
3542b15cb3dSCy Schubert }
3552b15cb3dSCy Schubert return 1;
3562b15cb3dSCy Schubert }
3572b15cb3dSCy Schubert
3582b15cb3dSCy Schubert void *
evthread_debug_get_real_lock_(void * lock_)3592b15cb3dSCy Schubert evthread_debug_get_real_lock_(void *lock_)
3602b15cb3dSCy Schubert {
3612b15cb3dSCy Schubert struct debug_lock *lock = lock_;
3622b15cb3dSCy Schubert return lock->lock;
3632b15cb3dSCy Schubert }
3642b15cb3dSCy Schubert
3652b15cb3dSCy Schubert void *
evthread_setup_global_lock_(void * lock_,unsigned locktype,int enable_locks)3662b15cb3dSCy Schubert evthread_setup_global_lock_(void *lock_, unsigned locktype, int enable_locks)
3672b15cb3dSCy Schubert {
3682b15cb3dSCy Schubert /* there are four cases here:
3692b15cb3dSCy Schubert 1) we're turning on debugging; locking is not on.
3702b15cb3dSCy Schubert 2) we're turning on debugging; locking is on.
3712b15cb3dSCy Schubert 3) we're turning on locking; debugging is not on.
3722b15cb3dSCy Schubert 4) we're turning on locking; debugging is on. */
3732b15cb3dSCy Schubert
3742b15cb3dSCy Schubert if (!enable_locks && original_lock_fns_.alloc == NULL) {
3752b15cb3dSCy Schubert /* Case 1: allocate a debug lock. */
3762b15cb3dSCy Schubert EVUTIL_ASSERT(lock_ == NULL);
3772b15cb3dSCy Schubert return debug_lock_alloc(locktype);
3782b15cb3dSCy Schubert } else if (!enable_locks && original_lock_fns_.alloc != NULL) {
3792b15cb3dSCy Schubert /* Case 2: wrap the lock in a debug lock. */
3802b15cb3dSCy Schubert struct debug_lock *lock;
3812b15cb3dSCy Schubert EVUTIL_ASSERT(lock_ != NULL);
3822b15cb3dSCy Schubert
3832b15cb3dSCy Schubert if (!(locktype & EVTHREAD_LOCKTYPE_RECURSIVE)) {
3842b15cb3dSCy Schubert /* We can't wrap it: We need a recursive lock */
3852b15cb3dSCy Schubert original_lock_fns_.free(lock_, locktype);
3862b15cb3dSCy Schubert return debug_lock_alloc(locktype);
3872b15cb3dSCy Schubert }
3882b15cb3dSCy Schubert lock = mm_malloc(sizeof(struct debug_lock));
3892b15cb3dSCy Schubert if (!lock) {
3902b15cb3dSCy Schubert original_lock_fns_.free(lock_, locktype);
3912b15cb3dSCy Schubert return NULL;
3922b15cb3dSCy Schubert }
3932b15cb3dSCy Schubert lock->lock = lock_;
3942b15cb3dSCy Schubert lock->locktype = locktype;
3952b15cb3dSCy Schubert lock->count = 0;
3962b15cb3dSCy Schubert lock->held_by = 0;
3972b15cb3dSCy Schubert return lock;
3982b15cb3dSCy Schubert } else if (enable_locks && ! evthread_lock_debugging_enabled_) {
3992b15cb3dSCy Schubert /* Case 3: allocate a regular lock */
4002b15cb3dSCy Schubert EVUTIL_ASSERT(lock_ == NULL);
4012b15cb3dSCy Schubert return evthread_lock_fns_.alloc(locktype);
4022b15cb3dSCy Schubert } else {
4032b15cb3dSCy Schubert /* Case 4: Fill in a debug lock with a real lock */
404*a466cc55SCy Schubert struct debug_lock *lock = lock_ ? lock_ : debug_lock_alloc(locktype);
4052b15cb3dSCy Schubert EVUTIL_ASSERT(enable_locks &&
4062b15cb3dSCy Schubert evthread_lock_debugging_enabled_);
4072b15cb3dSCy Schubert EVUTIL_ASSERT(lock->locktype == locktype);
408*a466cc55SCy Schubert if (!lock->lock) {
4092b15cb3dSCy Schubert lock->lock = original_lock_fns_.alloc(
4102b15cb3dSCy Schubert locktype|EVTHREAD_LOCKTYPE_RECURSIVE);
4112b15cb3dSCy Schubert if (!lock->lock) {
4122b15cb3dSCy Schubert lock->count = -200;
4132b15cb3dSCy Schubert mm_free(lock);
4142b15cb3dSCy Schubert return NULL;
4152b15cb3dSCy Schubert }
416*a466cc55SCy Schubert }
4172b15cb3dSCy Schubert return lock;
4182b15cb3dSCy Schubert }
4192b15cb3dSCy Schubert }
4202b15cb3dSCy Schubert
4212b15cb3dSCy Schubert
4222b15cb3dSCy Schubert #ifndef EVTHREAD_EXPOSE_STRUCTS
4232b15cb3dSCy Schubert unsigned long
evthreadimpl_get_id_()4242b15cb3dSCy Schubert evthreadimpl_get_id_()
4252b15cb3dSCy Schubert {
4262b15cb3dSCy Schubert return evthread_id_fn_ ? evthread_id_fn_() : 1;
4272b15cb3dSCy Schubert }
4282b15cb3dSCy Schubert void *
evthreadimpl_lock_alloc_(unsigned locktype)4292b15cb3dSCy Schubert evthreadimpl_lock_alloc_(unsigned locktype)
4302b15cb3dSCy Schubert {
431*a466cc55SCy Schubert #ifndef EVENT__DISABLE_DEBUG_MODE
432*a466cc55SCy Schubert if (event_debug_mode_on_) {
433*a466cc55SCy Schubert event_debug_created_threadable_ctx_ = 1;
434*a466cc55SCy Schubert }
435*a466cc55SCy Schubert #endif
436*a466cc55SCy Schubert
4372b15cb3dSCy Schubert return evthread_lock_fns_.alloc ?
4382b15cb3dSCy Schubert evthread_lock_fns_.alloc(locktype) : NULL;
4392b15cb3dSCy Schubert }
4402b15cb3dSCy Schubert void
evthreadimpl_lock_free_(void * lock,unsigned locktype)4412b15cb3dSCy Schubert evthreadimpl_lock_free_(void *lock, unsigned locktype)
4422b15cb3dSCy Schubert {
4432b15cb3dSCy Schubert if (evthread_lock_fns_.free)
4442b15cb3dSCy Schubert evthread_lock_fns_.free(lock, locktype);
4452b15cb3dSCy Schubert }
4462b15cb3dSCy Schubert int
evthreadimpl_lock_lock_(unsigned mode,void * lock)4472b15cb3dSCy Schubert evthreadimpl_lock_lock_(unsigned mode, void *lock)
4482b15cb3dSCy Schubert {
4492b15cb3dSCy Schubert if (evthread_lock_fns_.lock)
4502b15cb3dSCy Schubert return evthread_lock_fns_.lock(mode, lock);
4512b15cb3dSCy Schubert else
4522b15cb3dSCy Schubert return 0;
4532b15cb3dSCy Schubert }
4542b15cb3dSCy Schubert int
evthreadimpl_lock_unlock_(unsigned mode,void * lock)4552b15cb3dSCy Schubert evthreadimpl_lock_unlock_(unsigned mode, void *lock)
4562b15cb3dSCy Schubert {
4572b15cb3dSCy Schubert if (evthread_lock_fns_.unlock)
4582b15cb3dSCy Schubert return evthread_lock_fns_.unlock(mode, lock);
4592b15cb3dSCy Schubert else
4602b15cb3dSCy Schubert return 0;
4612b15cb3dSCy Schubert }
4622b15cb3dSCy Schubert void *
evthreadimpl_cond_alloc_(unsigned condtype)4632b15cb3dSCy Schubert evthreadimpl_cond_alloc_(unsigned condtype)
4642b15cb3dSCy Schubert {
465*a466cc55SCy Schubert #ifndef EVENT__DISABLE_DEBUG_MODE
466*a466cc55SCy Schubert if (event_debug_mode_on_) {
467*a466cc55SCy Schubert event_debug_created_threadable_ctx_ = 1;
468*a466cc55SCy Schubert }
469*a466cc55SCy Schubert #endif
470*a466cc55SCy Schubert
4712b15cb3dSCy Schubert return evthread_cond_fns_.alloc_condition ?
4722b15cb3dSCy Schubert evthread_cond_fns_.alloc_condition(condtype) : NULL;
4732b15cb3dSCy Schubert }
4742b15cb3dSCy Schubert void
evthreadimpl_cond_free_(void * cond)4752b15cb3dSCy Schubert evthreadimpl_cond_free_(void *cond)
4762b15cb3dSCy Schubert {
4772b15cb3dSCy Schubert if (evthread_cond_fns_.free_condition)
4782b15cb3dSCy Schubert evthread_cond_fns_.free_condition(cond);
4792b15cb3dSCy Schubert }
4802b15cb3dSCy Schubert int
evthreadimpl_cond_signal_(void * cond,int broadcast)4812b15cb3dSCy Schubert evthreadimpl_cond_signal_(void *cond, int broadcast)
4822b15cb3dSCy Schubert {
4832b15cb3dSCy Schubert if (evthread_cond_fns_.signal_condition)
4842b15cb3dSCy Schubert return evthread_cond_fns_.signal_condition(cond, broadcast);
4852b15cb3dSCy Schubert else
4862b15cb3dSCy Schubert return 0;
4872b15cb3dSCy Schubert }
4882b15cb3dSCy Schubert int
evthreadimpl_cond_wait_(void * cond,void * lock,const struct timeval * tv)4892b15cb3dSCy Schubert evthreadimpl_cond_wait_(void *cond, void *lock, const struct timeval *tv)
4902b15cb3dSCy Schubert {
4912b15cb3dSCy Schubert if (evthread_cond_fns_.wait_condition)
4922b15cb3dSCy Schubert return evthread_cond_fns_.wait_condition(cond, lock, tv);
4932b15cb3dSCy Schubert else
4942b15cb3dSCy Schubert return 0;
4952b15cb3dSCy Schubert }
4962b15cb3dSCy Schubert int
evthreadimpl_is_lock_debugging_enabled_(void)4972b15cb3dSCy Schubert evthreadimpl_is_lock_debugging_enabled_(void)
4982b15cb3dSCy Schubert {
4992b15cb3dSCy Schubert return evthread_lock_debugging_enabled_;
5002b15cb3dSCy Schubert }
5012b15cb3dSCy Schubert
5022b15cb3dSCy Schubert int
evthreadimpl_locking_enabled_(void)5032b15cb3dSCy Schubert evthreadimpl_locking_enabled_(void)
5042b15cb3dSCy Schubert {
5052b15cb3dSCy Schubert return evthread_lock_fns_.lock != NULL;
5062b15cb3dSCy Schubert }
5072b15cb3dSCy Schubert #endif
5082b15cb3dSCy Schubert
5092b15cb3dSCy Schubert #endif
510