1*663afb9bSAndroid Build Coastguard Worker /*
2*663afb9bSAndroid Build Coastguard Worker * Copyright (c) 2008-2012 Niels Provos, Nick Mathewson
3*663afb9bSAndroid Build Coastguard Worker *
4*663afb9bSAndroid Build Coastguard Worker * Redistribution and use in source and binary forms, with or without
5*663afb9bSAndroid Build Coastguard Worker * modification, are permitted provided that the following conditions
6*663afb9bSAndroid Build Coastguard Worker * are met:
7*663afb9bSAndroid Build Coastguard Worker * 1. Redistributions of source code must retain the above copyright
8*663afb9bSAndroid Build Coastguard Worker * notice, this list of conditions and the following disclaimer.
9*663afb9bSAndroid Build Coastguard Worker * 2. Redistributions in binary form must reproduce the above copyright
10*663afb9bSAndroid Build Coastguard Worker * notice, this list of conditions and the following disclaimer in the
11*663afb9bSAndroid Build Coastguard Worker * documentation and/or other materials provided with the distribution.
12*663afb9bSAndroid Build Coastguard Worker * 3. The name of the author may not be used to endorse or promote products
13*663afb9bSAndroid Build Coastguard Worker * derived from this software without specific prior written permission.
14*663afb9bSAndroid Build Coastguard Worker *
15*663afb9bSAndroid Build Coastguard Worker * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16*663afb9bSAndroid Build Coastguard Worker * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17*663afb9bSAndroid Build Coastguard Worker * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18*663afb9bSAndroid Build Coastguard Worker * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19*663afb9bSAndroid Build Coastguard Worker * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20*663afb9bSAndroid Build Coastguard Worker * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21*663afb9bSAndroid Build Coastguard Worker * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22*663afb9bSAndroid Build Coastguard Worker * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23*663afb9bSAndroid Build Coastguard Worker * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24*663afb9bSAndroid Build Coastguard Worker * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25*663afb9bSAndroid Build Coastguard Worker */
26*663afb9bSAndroid Build Coastguard Worker
27*663afb9bSAndroid Build Coastguard Worker #include "event2/event-config.h"
28*663afb9bSAndroid Build Coastguard Worker #include "evconfig-private.h"
29*663afb9bSAndroid Build Coastguard Worker
30*663afb9bSAndroid Build Coastguard Worker #ifndef EVENT__DISABLE_THREAD_SUPPORT
31*663afb9bSAndroid Build Coastguard Worker
32*663afb9bSAndroid Build Coastguard Worker #include "event2/thread.h"
33*663afb9bSAndroid Build Coastguard Worker
34*663afb9bSAndroid Build Coastguard Worker #include <stdlib.h>
35*663afb9bSAndroid Build Coastguard Worker #include <string.h>
36*663afb9bSAndroid Build Coastguard Worker
37*663afb9bSAndroid Build Coastguard Worker #include "log-internal.h"
38*663afb9bSAndroid Build Coastguard Worker #include "mm-internal.h"
39*663afb9bSAndroid Build Coastguard Worker #include "util-internal.h"
40*663afb9bSAndroid Build Coastguard Worker #include "evthread-internal.h"
41*663afb9bSAndroid Build Coastguard Worker
42*663afb9bSAndroid Build Coastguard Worker #ifdef EVTHREAD_EXPOSE_STRUCTS
43*663afb9bSAndroid Build Coastguard Worker #define GLOBAL
44*663afb9bSAndroid Build Coastguard Worker #else
45*663afb9bSAndroid Build Coastguard Worker #define GLOBAL static
46*663afb9bSAndroid Build Coastguard Worker #endif
47*663afb9bSAndroid Build Coastguard Worker
48*663afb9bSAndroid Build Coastguard Worker #ifndef EVENT__DISABLE_DEBUG_MODE
49*663afb9bSAndroid Build Coastguard Worker extern int event_debug_created_threadable_ctx_;
50*663afb9bSAndroid Build Coastguard Worker extern int event_debug_mode_on_;
51*663afb9bSAndroid Build Coastguard Worker #endif
52*663afb9bSAndroid Build Coastguard Worker
53*663afb9bSAndroid Build Coastguard Worker /* globals */
54*663afb9bSAndroid Build Coastguard Worker GLOBAL int evthread_lock_debugging_enabled_ = 0;
55*663afb9bSAndroid Build Coastguard Worker GLOBAL struct evthread_lock_callbacks evthread_lock_fns_ = {
56*663afb9bSAndroid Build Coastguard Worker 0, 0, NULL, NULL, NULL, NULL
57*663afb9bSAndroid Build Coastguard Worker };
58*663afb9bSAndroid Build Coastguard Worker GLOBAL unsigned long (*evthread_id_fn_)(void) = NULL;
59*663afb9bSAndroid Build Coastguard Worker GLOBAL struct evthread_condition_callbacks evthread_cond_fns_ = {
60*663afb9bSAndroid Build Coastguard Worker 0, NULL, NULL, NULL, NULL
61*663afb9bSAndroid Build Coastguard Worker };
62*663afb9bSAndroid Build Coastguard Worker
63*663afb9bSAndroid Build Coastguard Worker /* Used for debugging */
64*663afb9bSAndroid Build Coastguard Worker static struct evthread_lock_callbacks original_lock_fns_ = {
65*663afb9bSAndroid Build Coastguard Worker 0, 0, NULL, NULL, NULL, NULL
66*663afb9bSAndroid Build Coastguard Worker };
67*663afb9bSAndroid Build Coastguard Worker static struct evthread_condition_callbacks original_cond_fns_ = {
68*663afb9bSAndroid Build Coastguard Worker 0, NULL, NULL, NULL, NULL
69*663afb9bSAndroid Build Coastguard Worker };
70*663afb9bSAndroid Build Coastguard Worker
71*663afb9bSAndroid Build Coastguard Worker void
evthread_set_id_callback(unsigned long (* id_fn)(void))72*663afb9bSAndroid Build Coastguard Worker evthread_set_id_callback(unsigned long (*id_fn)(void))
73*663afb9bSAndroid Build Coastguard Worker {
74*663afb9bSAndroid Build Coastguard Worker evthread_id_fn_ = id_fn;
75*663afb9bSAndroid Build Coastguard Worker }
76*663afb9bSAndroid Build Coastguard Worker
evthread_get_lock_callbacks()77*663afb9bSAndroid Build Coastguard Worker struct evthread_lock_callbacks *evthread_get_lock_callbacks()
78*663afb9bSAndroid Build Coastguard Worker {
79*663afb9bSAndroid Build Coastguard Worker return evthread_lock_debugging_enabled_
80*663afb9bSAndroid Build Coastguard Worker ? &original_lock_fns_ : &evthread_lock_fns_;
81*663afb9bSAndroid Build Coastguard Worker }
evthread_get_condition_callbacks()82*663afb9bSAndroid Build Coastguard Worker struct evthread_condition_callbacks *evthread_get_condition_callbacks()
83*663afb9bSAndroid Build Coastguard Worker {
84*663afb9bSAndroid Build Coastguard Worker return evthread_lock_debugging_enabled_
85*663afb9bSAndroid Build Coastguard Worker ? &original_cond_fns_ : &evthread_cond_fns_;
86*663afb9bSAndroid Build Coastguard Worker }
evthreadimpl_disable_lock_debugging_(void)87*663afb9bSAndroid Build Coastguard Worker void evthreadimpl_disable_lock_debugging_(void)
88*663afb9bSAndroid Build Coastguard Worker {
89*663afb9bSAndroid Build Coastguard Worker evthread_lock_debugging_enabled_ = 0;
90*663afb9bSAndroid Build Coastguard Worker }
91*663afb9bSAndroid Build Coastguard Worker
92*663afb9bSAndroid Build Coastguard Worker int
evthread_set_lock_callbacks(const struct evthread_lock_callbacks * cbs)93*663afb9bSAndroid Build Coastguard Worker evthread_set_lock_callbacks(const struct evthread_lock_callbacks *cbs)
94*663afb9bSAndroid Build Coastguard Worker {
95*663afb9bSAndroid Build Coastguard Worker struct evthread_lock_callbacks *target = evthread_get_lock_callbacks();
96*663afb9bSAndroid Build Coastguard Worker
97*663afb9bSAndroid Build Coastguard Worker #ifndef EVENT__DISABLE_DEBUG_MODE
98*663afb9bSAndroid Build Coastguard Worker if (event_debug_mode_on_) {
99*663afb9bSAndroid Build Coastguard Worker if (event_debug_created_threadable_ctx_) {
100*663afb9bSAndroid Build Coastguard Worker event_errx(1, "evthread initialization must be called BEFORE anything else!");
101*663afb9bSAndroid Build Coastguard Worker }
102*663afb9bSAndroid Build Coastguard Worker }
103*663afb9bSAndroid Build Coastguard Worker #endif
104*663afb9bSAndroid Build Coastguard Worker
105*663afb9bSAndroid Build Coastguard Worker if (!cbs) {
106*663afb9bSAndroid Build Coastguard Worker if (target->alloc)
107*663afb9bSAndroid Build Coastguard Worker event_warnx("Trying to disable lock functions after "
108*663afb9bSAndroid Build Coastguard Worker "they have been set up will probaby not work.");
109*663afb9bSAndroid Build Coastguard Worker memset(target, 0, sizeof(evthread_lock_fns_));
110*663afb9bSAndroid Build Coastguard Worker return 0;
111*663afb9bSAndroid Build Coastguard Worker }
112*663afb9bSAndroid Build Coastguard Worker if (target->alloc) {
113*663afb9bSAndroid Build Coastguard Worker /* Uh oh; we already had locking callbacks set up.*/
114*663afb9bSAndroid Build Coastguard Worker if (target->lock_api_version == cbs->lock_api_version &&
115*663afb9bSAndroid Build Coastguard Worker target->supported_locktypes == cbs->supported_locktypes &&
116*663afb9bSAndroid Build Coastguard Worker target->alloc == cbs->alloc &&
117*663afb9bSAndroid Build Coastguard Worker target->free == cbs->free &&
118*663afb9bSAndroid Build Coastguard Worker target->lock == cbs->lock &&
119*663afb9bSAndroid Build Coastguard Worker target->unlock == cbs->unlock) {
120*663afb9bSAndroid Build Coastguard Worker /* no change -- allow this. */
121*663afb9bSAndroid Build Coastguard Worker return 0;
122*663afb9bSAndroid Build Coastguard Worker }
123*663afb9bSAndroid Build Coastguard Worker event_warnx("Can't change lock callbacks once they have been "
124*663afb9bSAndroid Build Coastguard Worker "initialized.");
125*663afb9bSAndroid Build Coastguard Worker return -1;
126*663afb9bSAndroid Build Coastguard Worker }
127*663afb9bSAndroid Build Coastguard Worker if (cbs->alloc && cbs->free && cbs->lock && cbs->unlock) {
128*663afb9bSAndroid Build Coastguard Worker memcpy(target, cbs, sizeof(evthread_lock_fns_));
129*663afb9bSAndroid Build Coastguard Worker return event_global_setup_locks_(1);
130*663afb9bSAndroid Build Coastguard Worker } else {
131*663afb9bSAndroid Build Coastguard Worker return -1;
132*663afb9bSAndroid Build Coastguard Worker }
133*663afb9bSAndroid Build Coastguard Worker }
134*663afb9bSAndroid Build Coastguard Worker
135*663afb9bSAndroid Build Coastguard Worker int
evthread_set_condition_callbacks(const struct evthread_condition_callbacks * cbs)136*663afb9bSAndroid Build Coastguard Worker evthread_set_condition_callbacks(const struct evthread_condition_callbacks *cbs)
137*663afb9bSAndroid Build Coastguard Worker {
138*663afb9bSAndroid Build Coastguard Worker struct evthread_condition_callbacks *target = evthread_get_condition_callbacks();
139*663afb9bSAndroid Build Coastguard Worker
140*663afb9bSAndroid Build Coastguard Worker #ifndef EVENT__DISABLE_DEBUG_MODE
141*663afb9bSAndroid Build Coastguard Worker if (event_debug_mode_on_) {
142*663afb9bSAndroid Build Coastguard Worker if (event_debug_created_threadable_ctx_) {
143*663afb9bSAndroid Build Coastguard Worker event_errx(1, "evthread initialization must be called BEFORE anything else!");
144*663afb9bSAndroid Build Coastguard Worker }
145*663afb9bSAndroid Build Coastguard Worker }
146*663afb9bSAndroid Build Coastguard Worker #endif
147*663afb9bSAndroid Build Coastguard Worker
148*663afb9bSAndroid Build Coastguard Worker if (!cbs) {
149*663afb9bSAndroid Build Coastguard Worker if (target->alloc_condition)
150*663afb9bSAndroid Build Coastguard Worker event_warnx("Trying to disable condition functions "
151*663afb9bSAndroid Build Coastguard Worker "after they have been set up will probaby not "
152*663afb9bSAndroid Build Coastguard Worker "work.");
153*663afb9bSAndroid Build Coastguard Worker memset(target, 0, sizeof(evthread_cond_fns_));
154*663afb9bSAndroid Build Coastguard Worker return 0;
155*663afb9bSAndroid Build Coastguard Worker }
156*663afb9bSAndroid Build Coastguard Worker if (target->alloc_condition) {
157*663afb9bSAndroid Build Coastguard Worker /* Uh oh; we already had condition callbacks set up.*/
158*663afb9bSAndroid Build Coastguard Worker if (target->condition_api_version == cbs->condition_api_version &&
159*663afb9bSAndroid Build Coastguard Worker target->alloc_condition == cbs->alloc_condition &&
160*663afb9bSAndroid Build Coastguard Worker target->free_condition == cbs->free_condition &&
161*663afb9bSAndroid Build Coastguard Worker target->signal_condition == cbs->signal_condition &&
162*663afb9bSAndroid Build Coastguard Worker target->wait_condition == cbs->wait_condition) {
163*663afb9bSAndroid Build Coastguard Worker /* no change -- allow this. */
164*663afb9bSAndroid Build Coastguard Worker return 0;
165*663afb9bSAndroid Build Coastguard Worker }
166*663afb9bSAndroid Build Coastguard Worker event_warnx("Can't change condition callbacks once they "
167*663afb9bSAndroid Build Coastguard Worker "have been initialized.");
168*663afb9bSAndroid Build Coastguard Worker return -1;
169*663afb9bSAndroid Build Coastguard Worker }
170*663afb9bSAndroid Build Coastguard Worker if (cbs->alloc_condition && cbs->free_condition &&
171*663afb9bSAndroid Build Coastguard Worker cbs->signal_condition && cbs->wait_condition) {
172*663afb9bSAndroid Build Coastguard Worker memcpy(target, cbs, sizeof(evthread_cond_fns_));
173*663afb9bSAndroid Build Coastguard Worker }
174*663afb9bSAndroid Build Coastguard Worker if (evthread_lock_debugging_enabled_) {
175*663afb9bSAndroid Build Coastguard Worker evthread_cond_fns_.alloc_condition = cbs->alloc_condition;
176*663afb9bSAndroid Build Coastguard Worker evthread_cond_fns_.free_condition = cbs->free_condition;
177*663afb9bSAndroid Build Coastguard Worker evthread_cond_fns_.signal_condition = cbs->signal_condition;
178*663afb9bSAndroid Build Coastguard Worker }
179*663afb9bSAndroid Build Coastguard Worker return 0;
180*663afb9bSAndroid Build Coastguard Worker }
181*663afb9bSAndroid Build Coastguard Worker
182*663afb9bSAndroid Build Coastguard Worker #define DEBUG_LOCK_SIG 0xdeb0b10c
183*663afb9bSAndroid Build Coastguard Worker
184*663afb9bSAndroid Build Coastguard Worker struct debug_lock {
185*663afb9bSAndroid Build Coastguard Worker unsigned signature;
186*663afb9bSAndroid Build Coastguard Worker unsigned locktype;
187*663afb9bSAndroid Build Coastguard Worker unsigned long held_by;
188*663afb9bSAndroid Build Coastguard Worker /* XXXX if we ever use read-write locks, we will need a separate
189*663afb9bSAndroid Build Coastguard Worker * lock to protect count. */
190*663afb9bSAndroid Build Coastguard Worker int count;
191*663afb9bSAndroid Build Coastguard Worker void *lock;
192*663afb9bSAndroid Build Coastguard Worker };
193*663afb9bSAndroid Build Coastguard Worker
194*663afb9bSAndroid Build Coastguard Worker static void *
debug_lock_alloc(unsigned locktype)195*663afb9bSAndroid Build Coastguard Worker debug_lock_alloc(unsigned locktype)
196*663afb9bSAndroid Build Coastguard Worker {
197*663afb9bSAndroid Build Coastguard Worker struct debug_lock *result = mm_malloc(sizeof(struct debug_lock));
198*663afb9bSAndroid Build Coastguard Worker if (!result)
199*663afb9bSAndroid Build Coastguard Worker return NULL;
200*663afb9bSAndroid Build Coastguard Worker if (original_lock_fns_.alloc) {
201*663afb9bSAndroid Build Coastguard Worker if (!(result->lock = original_lock_fns_.alloc(
202*663afb9bSAndroid Build Coastguard Worker locktype|EVTHREAD_LOCKTYPE_RECURSIVE))) {
203*663afb9bSAndroid Build Coastguard Worker mm_free(result);
204*663afb9bSAndroid Build Coastguard Worker return NULL;
205*663afb9bSAndroid Build Coastguard Worker }
206*663afb9bSAndroid Build Coastguard Worker } else {
207*663afb9bSAndroid Build Coastguard Worker result->lock = NULL;
208*663afb9bSAndroid Build Coastguard Worker }
209*663afb9bSAndroid Build Coastguard Worker result->signature = DEBUG_LOCK_SIG;
210*663afb9bSAndroid Build Coastguard Worker result->locktype = locktype;
211*663afb9bSAndroid Build Coastguard Worker result->count = 0;
212*663afb9bSAndroid Build Coastguard Worker result->held_by = 0;
213*663afb9bSAndroid Build Coastguard Worker return result;
214*663afb9bSAndroid Build Coastguard Worker }
215*663afb9bSAndroid Build Coastguard Worker
216*663afb9bSAndroid Build Coastguard Worker static void
debug_lock_free(void * lock_,unsigned locktype)217*663afb9bSAndroid Build Coastguard Worker debug_lock_free(void *lock_, unsigned locktype)
218*663afb9bSAndroid Build Coastguard Worker {
219*663afb9bSAndroid Build Coastguard Worker struct debug_lock *lock = lock_;
220*663afb9bSAndroid Build Coastguard Worker EVUTIL_ASSERT(lock->count == 0);
221*663afb9bSAndroid Build Coastguard Worker EVUTIL_ASSERT(locktype == lock->locktype);
222*663afb9bSAndroid Build Coastguard Worker EVUTIL_ASSERT(DEBUG_LOCK_SIG == lock->signature);
223*663afb9bSAndroid Build Coastguard Worker if (original_lock_fns_.free) {
224*663afb9bSAndroid Build Coastguard Worker original_lock_fns_.free(lock->lock,
225*663afb9bSAndroid Build Coastguard Worker lock->locktype|EVTHREAD_LOCKTYPE_RECURSIVE);
226*663afb9bSAndroid Build Coastguard Worker }
227*663afb9bSAndroid Build Coastguard Worker lock->lock = NULL;
228*663afb9bSAndroid Build Coastguard Worker lock->count = -100;
229*663afb9bSAndroid Build Coastguard Worker lock->signature = 0x12300fda;
230*663afb9bSAndroid Build Coastguard Worker mm_free(lock);
231*663afb9bSAndroid Build Coastguard Worker }
232*663afb9bSAndroid Build Coastguard Worker
233*663afb9bSAndroid Build Coastguard Worker static void
evthread_debug_lock_mark_locked(unsigned mode,struct debug_lock * lock)234*663afb9bSAndroid Build Coastguard Worker evthread_debug_lock_mark_locked(unsigned mode, struct debug_lock *lock)
235*663afb9bSAndroid Build Coastguard Worker {
236*663afb9bSAndroid Build Coastguard Worker EVUTIL_ASSERT(DEBUG_LOCK_SIG == lock->signature);
237*663afb9bSAndroid Build Coastguard Worker ++lock->count;
238*663afb9bSAndroid Build Coastguard Worker if (!(lock->locktype & EVTHREAD_LOCKTYPE_RECURSIVE))
239*663afb9bSAndroid Build Coastguard Worker EVUTIL_ASSERT(lock->count == 1);
240*663afb9bSAndroid Build Coastguard Worker if (evthread_id_fn_) {
241*663afb9bSAndroid Build Coastguard Worker unsigned long me;
242*663afb9bSAndroid Build Coastguard Worker me = evthread_id_fn_();
243*663afb9bSAndroid Build Coastguard Worker if (lock->count > 1)
244*663afb9bSAndroid Build Coastguard Worker EVUTIL_ASSERT(lock->held_by == me);
245*663afb9bSAndroid Build Coastguard Worker lock->held_by = me;
246*663afb9bSAndroid Build Coastguard Worker }
247*663afb9bSAndroid Build Coastguard Worker }
248*663afb9bSAndroid Build Coastguard Worker
249*663afb9bSAndroid Build Coastguard Worker static int
debug_lock_lock(unsigned mode,void * lock_)250*663afb9bSAndroid Build Coastguard Worker debug_lock_lock(unsigned mode, void *lock_)
251*663afb9bSAndroid Build Coastguard Worker {
252*663afb9bSAndroid Build Coastguard Worker struct debug_lock *lock = lock_;
253*663afb9bSAndroid Build Coastguard Worker int res = 0;
254*663afb9bSAndroid Build Coastguard Worker if (lock->locktype & EVTHREAD_LOCKTYPE_READWRITE)
255*663afb9bSAndroid Build Coastguard Worker EVUTIL_ASSERT(mode & (EVTHREAD_READ|EVTHREAD_WRITE));
256*663afb9bSAndroid Build Coastguard Worker else
257*663afb9bSAndroid Build Coastguard Worker EVUTIL_ASSERT((mode & (EVTHREAD_READ|EVTHREAD_WRITE)) == 0);
258*663afb9bSAndroid Build Coastguard Worker if (original_lock_fns_.lock)
259*663afb9bSAndroid Build Coastguard Worker res = original_lock_fns_.lock(mode, lock->lock);
260*663afb9bSAndroid Build Coastguard Worker if (!res) {
261*663afb9bSAndroid Build Coastguard Worker evthread_debug_lock_mark_locked(mode, lock);
262*663afb9bSAndroid Build Coastguard Worker }
263*663afb9bSAndroid Build Coastguard Worker return res;
264*663afb9bSAndroid Build Coastguard Worker }
265*663afb9bSAndroid Build Coastguard Worker
266*663afb9bSAndroid Build Coastguard Worker static void
evthread_debug_lock_mark_unlocked(unsigned mode,struct debug_lock * lock)267*663afb9bSAndroid Build Coastguard Worker evthread_debug_lock_mark_unlocked(unsigned mode, struct debug_lock *lock)
268*663afb9bSAndroid Build Coastguard Worker {
269*663afb9bSAndroid Build Coastguard Worker EVUTIL_ASSERT(DEBUG_LOCK_SIG == lock->signature);
270*663afb9bSAndroid Build Coastguard Worker if (lock->locktype & EVTHREAD_LOCKTYPE_READWRITE)
271*663afb9bSAndroid Build Coastguard Worker EVUTIL_ASSERT(mode & (EVTHREAD_READ|EVTHREAD_WRITE));
272*663afb9bSAndroid Build Coastguard Worker else
273*663afb9bSAndroid Build Coastguard Worker EVUTIL_ASSERT((mode & (EVTHREAD_READ|EVTHREAD_WRITE)) == 0);
274*663afb9bSAndroid Build Coastguard Worker if (evthread_id_fn_) {
275*663afb9bSAndroid Build Coastguard Worker unsigned long me;
276*663afb9bSAndroid Build Coastguard Worker me = evthread_id_fn_();
277*663afb9bSAndroid Build Coastguard Worker EVUTIL_ASSERT(lock->held_by == me);
278*663afb9bSAndroid Build Coastguard Worker if (lock->count == 1)
279*663afb9bSAndroid Build Coastguard Worker lock->held_by = 0;
280*663afb9bSAndroid Build Coastguard Worker }
281*663afb9bSAndroid Build Coastguard Worker --lock->count;
282*663afb9bSAndroid Build Coastguard Worker EVUTIL_ASSERT(lock->count >= 0);
283*663afb9bSAndroid Build Coastguard Worker }
284*663afb9bSAndroid Build Coastguard Worker
285*663afb9bSAndroid Build Coastguard Worker static int
debug_lock_unlock(unsigned mode,void * lock_)286*663afb9bSAndroid Build Coastguard Worker debug_lock_unlock(unsigned mode, void *lock_)
287*663afb9bSAndroid Build Coastguard Worker {
288*663afb9bSAndroid Build Coastguard Worker struct debug_lock *lock = lock_;
289*663afb9bSAndroid Build Coastguard Worker int res = 0;
290*663afb9bSAndroid Build Coastguard Worker evthread_debug_lock_mark_unlocked(mode, lock);
291*663afb9bSAndroid Build Coastguard Worker if (original_lock_fns_.unlock)
292*663afb9bSAndroid Build Coastguard Worker res = original_lock_fns_.unlock(mode, lock->lock);
293*663afb9bSAndroid Build Coastguard Worker return res;
294*663afb9bSAndroid Build Coastguard Worker }
295*663afb9bSAndroid Build Coastguard Worker
296*663afb9bSAndroid Build Coastguard Worker static int
debug_cond_wait(void * cond_,void * lock_,const struct timeval * tv)297*663afb9bSAndroid Build Coastguard Worker debug_cond_wait(void *cond_, void *lock_, const struct timeval *tv)
298*663afb9bSAndroid Build Coastguard Worker {
299*663afb9bSAndroid Build Coastguard Worker int r;
300*663afb9bSAndroid Build Coastguard Worker struct debug_lock *lock = lock_;
301*663afb9bSAndroid Build Coastguard Worker EVUTIL_ASSERT(lock);
302*663afb9bSAndroid Build Coastguard Worker EVUTIL_ASSERT(DEBUG_LOCK_SIG == lock->signature);
303*663afb9bSAndroid Build Coastguard Worker EVLOCK_ASSERT_LOCKED(lock_);
304*663afb9bSAndroid Build Coastguard Worker evthread_debug_lock_mark_unlocked(0, lock);
305*663afb9bSAndroid Build Coastguard Worker r = original_cond_fns_.wait_condition(cond_, lock->lock, tv);
306*663afb9bSAndroid Build Coastguard Worker evthread_debug_lock_mark_locked(0, lock);
307*663afb9bSAndroid Build Coastguard Worker return r;
308*663afb9bSAndroid Build Coastguard Worker }
309*663afb9bSAndroid Build Coastguard Worker
310*663afb9bSAndroid Build Coastguard Worker /* misspelled version for backward compatibility */
311*663afb9bSAndroid Build Coastguard Worker void
evthread_enable_lock_debuging(void)312*663afb9bSAndroid Build Coastguard Worker evthread_enable_lock_debuging(void)
313*663afb9bSAndroid Build Coastguard Worker {
314*663afb9bSAndroid Build Coastguard Worker evthread_enable_lock_debugging();
315*663afb9bSAndroid Build Coastguard Worker }
316*663afb9bSAndroid Build Coastguard Worker
317*663afb9bSAndroid Build Coastguard Worker void
evthread_enable_lock_debugging(void)318*663afb9bSAndroid Build Coastguard Worker evthread_enable_lock_debugging(void)
319*663afb9bSAndroid Build Coastguard Worker {
320*663afb9bSAndroid Build Coastguard Worker struct evthread_lock_callbacks cbs = {
321*663afb9bSAndroid Build Coastguard Worker EVTHREAD_LOCK_API_VERSION,
322*663afb9bSAndroid Build Coastguard Worker EVTHREAD_LOCKTYPE_RECURSIVE,
323*663afb9bSAndroid Build Coastguard Worker debug_lock_alloc,
324*663afb9bSAndroid Build Coastguard Worker debug_lock_free,
325*663afb9bSAndroid Build Coastguard Worker debug_lock_lock,
326*663afb9bSAndroid Build Coastguard Worker debug_lock_unlock
327*663afb9bSAndroid Build Coastguard Worker };
328*663afb9bSAndroid Build Coastguard Worker if (evthread_lock_debugging_enabled_)
329*663afb9bSAndroid Build Coastguard Worker return;
330*663afb9bSAndroid Build Coastguard Worker memcpy(&original_lock_fns_, &evthread_lock_fns_,
331*663afb9bSAndroid Build Coastguard Worker sizeof(struct evthread_lock_callbacks));
332*663afb9bSAndroid Build Coastguard Worker memcpy(&evthread_lock_fns_, &cbs,
333*663afb9bSAndroid Build Coastguard Worker sizeof(struct evthread_lock_callbacks));
334*663afb9bSAndroid Build Coastguard Worker
335*663afb9bSAndroid Build Coastguard Worker memcpy(&original_cond_fns_, &evthread_cond_fns_,
336*663afb9bSAndroid Build Coastguard Worker sizeof(struct evthread_condition_callbacks));
337*663afb9bSAndroid Build Coastguard Worker evthread_cond_fns_.wait_condition = debug_cond_wait;
338*663afb9bSAndroid Build Coastguard Worker evthread_lock_debugging_enabled_ = 1;
339*663afb9bSAndroid Build Coastguard Worker
340*663afb9bSAndroid Build Coastguard Worker /* XXX return value should get checked. */
341*663afb9bSAndroid Build Coastguard Worker event_global_setup_locks_(0);
342*663afb9bSAndroid Build Coastguard Worker }
343*663afb9bSAndroid Build Coastguard Worker
344*663afb9bSAndroid Build Coastguard Worker int
evthread_is_debug_lock_held_(void * lock_)345*663afb9bSAndroid Build Coastguard Worker evthread_is_debug_lock_held_(void *lock_)
346*663afb9bSAndroid Build Coastguard Worker {
347*663afb9bSAndroid Build Coastguard Worker struct debug_lock *lock = lock_;
348*663afb9bSAndroid Build Coastguard Worker if (! lock->count)
349*663afb9bSAndroid Build Coastguard Worker return 0;
350*663afb9bSAndroid Build Coastguard Worker if (evthread_id_fn_) {
351*663afb9bSAndroid Build Coastguard Worker unsigned long me = evthread_id_fn_();
352*663afb9bSAndroid Build Coastguard Worker if (lock->held_by != me)
353*663afb9bSAndroid Build Coastguard Worker return 0;
354*663afb9bSAndroid Build Coastguard Worker }
355*663afb9bSAndroid Build Coastguard Worker return 1;
356*663afb9bSAndroid Build Coastguard Worker }
357*663afb9bSAndroid Build Coastguard Worker
358*663afb9bSAndroid Build Coastguard Worker void *
evthread_debug_get_real_lock_(void * lock_)359*663afb9bSAndroid Build Coastguard Worker evthread_debug_get_real_lock_(void *lock_)
360*663afb9bSAndroid Build Coastguard Worker {
361*663afb9bSAndroid Build Coastguard Worker struct debug_lock *lock = lock_;
362*663afb9bSAndroid Build Coastguard Worker return lock->lock;
363*663afb9bSAndroid Build Coastguard Worker }
364*663afb9bSAndroid Build Coastguard Worker
365*663afb9bSAndroid Build Coastguard Worker void *
evthread_setup_global_lock_(void * lock_,unsigned locktype,int enable_locks)366*663afb9bSAndroid Build Coastguard Worker evthread_setup_global_lock_(void *lock_, unsigned locktype, int enable_locks)
367*663afb9bSAndroid Build Coastguard Worker {
368*663afb9bSAndroid Build Coastguard Worker /* there are four cases here:
369*663afb9bSAndroid Build Coastguard Worker 1) we're turning on debugging; locking is not on.
370*663afb9bSAndroid Build Coastguard Worker 2) we're turning on debugging; locking is on.
371*663afb9bSAndroid Build Coastguard Worker 3) we're turning on locking; debugging is not on.
372*663afb9bSAndroid Build Coastguard Worker 4) we're turning on locking; debugging is on. */
373*663afb9bSAndroid Build Coastguard Worker
374*663afb9bSAndroid Build Coastguard Worker if (!enable_locks && original_lock_fns_.alloc == NULL) {
375*663afb9bSAndroid Build Coastguard Worker /* Case 1: allocate a debug lock. */
376*663afb9bSAndroid Build Coastguard Worker EVUTIL_ASSERT(lock_ == NULL);
377*663afb9bSAndroid Build Coastguard Worker return debug_lock_alloc(locktype);
378*663afb9bSAndroid Build Coastguard Worker } else if (!enable_locks && original_lock_fns_.alloc != NULL) {
379*663afb9bSAndroid Build Coastguard Worker /* Case 2: wrap the lock in a debug lock. */
380*663afb9bSAndroid Build Coastguard Worker struct debug_lock *lock;
381*663afb9bSAndroid Build Coastguard Worker EVUTIL_ASSERT(lock_ != NULL);
382*663afb9bSAndroid Build Coastguard Worker
383*663afb9bSAndroid Build Coastguard Worker if (!(locktype & EVTHREAD_LOCKTYPE_RECURSIVE)) {
384*663afb9bSAndroid Build Coastguard Worker /* We can't wrap it: We need a recursive lock */
385*663afb9bSAndroid Build Coastguard Worker original_lock_fns_.free(lock_, locktype);
386*663afb9bSAndroid Build Coastguard Worker return debug_lock_alloc(locktype);
387*663afb9bSAndroid Build Coastguard Worker }
388*663afb9bSAndroid Build Coastguard Worker lock = mm_malloc(sizeof(struct debug_lock));
389*663afb9bSAndroid Build Coastguard Worker if (!lock) {
390*663afb9bSAndroid Build Coastguard Worker original_lock_fns_.free(lock_, locktype);
391*663afb9bSAndroid Build Coastguard Worker return NULL;
392*663afb9bSAndroid Build Coastguard Worker }
393*663afb9bSAndroid Build Coastguard Worker lock->lock = lock_;
394*663afb9bSAndroid Build Coastguard Worker lock->locktype = locktype;
395*663afb9bSAndroid Build Coastguard Worker lock->count = 0;
396*663afb9bSAndroid Build Coastguard Worker lock->held_by = 0;
397*663afb9bSAndroid Build Coastguard Worker return lock;
398*663afb9bSAndroid Build Coastguard Worker } else if (enable_locks && ! evthread_lock_debugging_enabled_) {
399*663afb9bSAndroid Build Coastguard Worker /* Case 3: allocate a regular lock */
400*663afb9bSAndroid Build Coastguard Worker EVUTIL_ASSERT(lock_ == NULL);
401*663afb9bSAndroid Build Coastguard Worker return evthread_lock_fns_.alloc(locktype);
402*663afb9bSAndroid Build Coastguard Worker } else {
403*663afb9bSAndroid Build Coastguard Worker /* Case 4: Fill in a debug lock with a real lock */
404*663afb9bSAndroid Build Coastguard Worker struct debug_lock *lock = lock_ ? lock_ : debug_lock_alloc(locktype);
405*663afb9bSAndroid Build Coastguard Worker EVUTIL_ASSERT(enable_locks &&
406*663afb9bSAndroid Build Coastguard Worker evthread_lock_debugging_enabled_);
407*663afb9bSAndroid Build Coastguard Worker EVUTIL_ASSERT(lock->locktype == locktype);
408*663afb9bSAndroid Build Coastguard Worker if (!lock->lock) {
409*663afb9bSAndroid Build Coastguard Worker lock->lock = original_lock_fns_.alloc(
410*663afb9bSAndroid Build Coastguard Worker locktype|EVTHREAD_LOCKTYPE_RECURSIVE);
411*663afb9bSAndroid Build Coastguard Worker if (!lock->lock) {
412*663afb9bSAndroid Build Coastguard Worker lock->count = -200;
413*663afb9bSAndroid Build Coastguard Worker mm_free(lock);
414*663afb9bSAndroid Build Coastguard Worker return NULL;
415*663afb9bSAndroid Build Coastguard Worker }
416*663afb9bSAndroid Build Coastguard Worker }
417*663afb9bSAndroid Build Coastguard Worker return lock;
418*663afb9bSAndroid Build Coastguard Worker }
419*663afb9bSAndroid Build Coastguard Worker }
420*663afb9bSAndroid Build Coastguard Worker
421*663afb9bSAndroid Build Coastguard Worker
422*663afb9bSAndroid Build Coastguard Worker #ifndef EVTHREAD_EXPOSE_STRUCTS
423*663afb9bSAndroid Build Coastguard Worker unsigned long
evthreadimpl_get_id_()424*663afb9bSAndroid Build Coastguard Worker evthreadimpl_get_id_()
425*663afb9bSAndroid Build Coastguard Worker {
426*663afb9bSAndroid Build Coastguard Worker return evthread_id_fn_ ? evthread_id_fn_() : 1;
427*663afb9bSAndroid Build Coastguard Worker }
428*663afb9bSAndroid Build Coastguard Worker void *
evthreadimpl_lock_alloc_(unsigned locktype)429*663afb9bSAndroid Build Coastguard Worker evthreadimpl_lock_alloc_(unsigned locktype)
430*663afb9bSAndroid Build Coastguard Worker {
431*663afb9bSAndroid Build Coastguard Worker #ifndef EVENT__DISABLE_DEBUG_MODE
432*663afb9bSAndroid Build Coastguard Worker if (event_debug_mode_on_) {
433*663afb9bSAndroid Build Coastguard Worker event_debug_created_threadable_ctx_ = 1;
434*663afb9bSAndroid Build Coastguard Worker }
435*663afb9bSAndroid Build Coastguard Worker #endif
436*663afb9bSAndroid Build Coastguard Worker
437*663afb9bSAndroid Build Coastguard Worker return evthread_lock_fns_.alloc ?
438*663afb9bSAndroid Build Coastguard Worker evthread_lock_fns_.alloc(locktype) : NULL;
439*663afb9bSAndroid Build Coastguard Worker }
440*663afb9bSAndroid Build Coastguard Worker void
evthreadimpl_lock_free_(void * lock,unsigned locktype)441*663afb9bSAndroid Build Coastguard Worker evthreadimpl_lock_free_(void *lock, unsigned locktype)
442*663afb9bSAndroid Build Coastguard Worker {
443*663afb9bSAndroid Build Coastguard Worker if (evthread_lock_fns_.free)
444*663afb9bSAndroid Build Coastguard Worker evthread_lock_fns_.free(lock, locktype);
445*663afb9bSAndroid Build Coastguard Worker }
446*663afb9bSAndroid Build Coastguard Worker int
evthreadimpl_lock_lock_(unsigned mode,void * lock)447*663afb9bSAndroid Build Coastguard Worker evthreadimpl_lock_lock_(unsigned mode, void *lock)
448*663afb9bSAndroid Build Coastguard Worker {
449*663afb9bSAndroid Build Coastguard Worker if (evthread_lock_fns_.lock)
450*663afb9bSAndroid Build Coastguard Worker return evthread_lock_fns_.lock(mode, lock);
451*663afb9bSAndroid Build Coastguard Worker else
452*663afb9bSAndroid Build Coastguard Worker return 0;
453*663afb9bSAndroid Build Coastguard Worker }
454*663afb9bSAndroid Build Coastguard Worker int
evthreadimpl_lock_unlock_(unsigned mode,void * lock)455*663afb9bSAndroid Build Coastguard Worker evthreadimpl_lock_unlock_(unsigned mode, void *lock)
456*663afb9bSAndroid Build Coastguard Worker {
457*663afb9bSAndroid Build Coastguard Worker if (evthread_lock_fns_.unlock)
458*663afb9bSAndroid Build Coastguard Worker return evthread_lock_fns_.unlock(mode, lock);
459*663afb9bSAndroid Build Coastguard Worker else
460*663afb9bSAndroid Build Coastguard Worker return 0;
461*663afb9bSAndroid Build Coastguard Worker }
462*663afb9bSAndroid Build Coastguard Worker void *
evthreadimpl_cond_alloc_(unsigned condtype)463*663afb9bSAndroid Build Coastguard Worker evthreadimpl_cond_alloc_(unsigned condtype)
464*663afb9bSAndroid Build Coastguard Worker {
465*663afb9bSAndroid Build Coastguard Worker #ifndef EVENT__DISABLE_DEBUG_MODE
466*663afb9bSAndroid Build Coastguard Worker if (event_debug_mode_on_) {
467*663afb9bSAndroid Build Coastguard Worker event_debug_created_threadable_ctx_ = 1;
468*663afb9bSAndroid Build Coastguard Worker }
469*663afb9bSAndroid Build Coastguard Worker #endif
470*663afb9bSAndroid Build Coastguard Worker
471*663afb9bSAndroid Build Coastguard Worker return evthread_cond_fns_.alloc_condition ?
472*663afb9bSAndroid Build Coastguard Worker evthread_cond_fns_.alloc_condition(condtype) : NULL;
473*663afb9bSAndroid Build Coastguard Worker }
474*663afb9bSAndroid Build Coastguard Worker void
evthreadimpl_cond_free_(void * cond)475*663afb9bSAndroid Build Coastguard Worker evthreadimpl_cond_free_(void *cond)
476*663afb9bSAndroid Build Coastguard Worker {
477*663afb9bSAndroid Build Coastguard Worker if (evthread_cond_fns_.free_condition)
478*663afb9bSAndroid Build Coastguard Worker evthread_cond_fns_.free_condition(cond);
479*663afb9bSAndroid Build Coastguard Worker }
480*663afb9bSAndroid Build Coastguard Worker int
evthreadimpl_cond_signal_(void * cond,int broadcast)481*663afb9bSAndroid Build Coastguard Worker evthreadimpl_cond_signal_(void *cond, int broadcast)
482*663afb9bSAndroid Build Coastguard Worker {
483*663afb9bSAndroid Build Coastguard Worker if (evthread_cond_fns_.signal_condition)
484*663afb9bSAndroid Build Coastguard Worker return evthread_cond_fns_.signal_condition(cond, broadcast);
485*663afb9bSAndroid Build Coastguard Worker else
486*663afb9bSAndroid Build Coastguard Worker return 0;
487*663afb9bSAndroid Build Coastguard Worker }
488*663afb9bSAndroid Build Coastguard Worker int
evthreadimpl_cond_wait_(void * cond,void * lock,const struct timeval * tv)489*663afb9bSAndroid Build Coastguard Worker evthreadimpl_cond_wait_(void *cond, void *lock, const struct timeval *tv)
490*663afb9bSAndroid Build Coastguard Worker {
491*663afb9bSAndroid Build Coastguard Worker if (evthread_cond_fns_.wait_condition)
492*663afb9bSAndroid Build Coastguard Worker return evthread_cond_fns_.wait_condition(cond, lock, tv);
493*663afb9bSAndroid Build Coastguard Worker else
494*663afb9bSAndroid Build Coastguard Worker return 0;
495*663afb9bSAndroid Build Coastguard Worker }
496*663afb9bSAndroid Build Coastguard Worker int
evthreadimpl_is_lock_debugging_enabled_(void)497*663afb9bSAndroid Build Coastguard Worker evthreadimpl_is_lock_debugging_enabled_(void)
498*663afb9bSAndroid Build Coastguard Worker {
499*663afb9bSAndroid Build Coastguard Worker return evthread_lock_debugging_enabled_;
500*663afb9bSAndroid Build Coastguard Worker }
501*663afb9bSAndroid Build Coastguard Worker
502*663afb9bSAndroid Build Coastguard Worker int
evthreadimpl_locking_enabled_(void)503*663afb9bSAndroid Build Coastguard Worker evthreadimpl_locking_enabled_(void)
504*663afb9bSAndroid Build Coastguard Worker {
505*663afb9bSAndroid Build Coastguard Worker return evthread_lock_fns_.lock != NULL;
506*663afb9bSAndroid Build Coastguard Worker }
507*663afb9bSAndroid Build Coastguard Worker #endif
508*663afb9bSAndroid Build Coastguard Worker
509*663afb9bSAndroid Build Coastguard Worker #endif
510