1275970Scy/*
2275970Scy * Copyright (c) 2008-2012 Niels Provos, Nick Mathewson
3275970Scy *
4275970Scy * Redistribution and use in source and binary forms, with or without
5275970Scy * modification, are permitted provided that the following conditions
6275970Scy * are met:
7275970Scy * 1. Redistributions of source code must retain the above copyright
8275970Scy *    notice, this list of conditions and the following disclaimer.
9275970Scy * 2. Redistributions in binary form must reproduce the above copyright
10275970Scy *    notice, this list of conditions and the following disclaimer in the
11275970Scy *    documentation and/or other materials provided with the distribution.
12275970Scy * 3. The name of the author may not be used to endorse or promote products
13275970Scy *    derived from this software without specific prior written permission.
14275970Scy *
15275970Scy * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16275970Scy * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17275970Scy * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18275970Scy * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19275970Scy * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20275970Scy * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21275970Scy * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22275970Scy * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23275970Scy * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24275970Scy * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25275970Scy */
26275970Scy
27275970Scy#include "event2/event-config.h"
28275970Scy#include "evconfig-private.h"
29275970Scy
30275970Scy#ifndef EVENT__DISABLE_THREAD_SUPPORT
31275970Scy
32275970Scy#include "event2/thread.h"
33275970Scy
34275970Scy#include <stdlib.h>
35275970Scy#include <string.h>
36275970Scy
37275970Scy#include "log-internal.h"
38275970Scy#include "mm-internal.h"
39275970Scy#include "util-internal.h"
40275970Scy#include "evthread-internal.h"
41275970Scy
42275970Scy#ifdef EVTHREAD_EXPOSE_STRUCTS
43275970Scy#define GLOBAL
44275970Scy#else
45275970Scy#define GLOBAL static
46275970Scy#endif
47275970Scy
48275970Scy/* globals */
49275970ScyGLOBAL int evthread_lock_debugging_enabled_ = 0;
50275970ScyGLOBAL struct evthread_lock_callbacks evthread_lock_fns_ = {
51275970Scy	0, 0, NULL, NULL, NULL, NULL
52275970Scy};
53275970ScyGLOBAL unsigned long (*evthread_id_fn_)(void) = NULL;
54275970ScyGLOBAL struct evthread_condition_callbacks evthread_cond_fns_ = {
55275970Scy	0, NULL, NULL, NULL, NULL
56275970Scy};
57275970Scy
58275970Scy/* Used for debugging */
59275970Scystatic struct evthread_lock_callbacks original_lock_fns_ = {
60275970Scy	0, 0, NULL, NULL, NULL, NULL
61275970Scy};
62275970Scystatic struct evthread_condition_callbacks original_cond_fns_ = {
63275970Scy	0, NULL, NULL, NULL, NULL
64275970Scy};
65275970Scy
66275970Scyvoid
67275970Scyevthread_set_id_callback(unsigned long (*id_fn)(void))
68275970Scy{
69275970Scy	evthread_id_fn_ = id_fn;
70275970Scy}
71275970Scy
72282408Scystruct evthread_lock_callbacks *evthread_get_lock_callbacks()
73282408Scy{
74282408Scy	return evthread_lock_debugging_enabled_
75282408Scy	    ? &original_lock_fns_ : &evthread_lock_fns_;
76282408Scy}
77282408Scystruct evthread_condition_callbacks *evthread_get_condition_callbacks()
78282408Scy{
79282408Scy	return evthread_lock_debugging_enabled_
80282408Scy	    ? &original_cond_fns_ : &evthread_cond_fns_;
81282408Scy}
82282408Scyvoid evthreadimpl_disable_lock_debugging_(void)
83282408Scy{
84282408Scy	evthread_lock_debugging_enabled_ = 0;
85282408Scy}
86282408Scy
87275970Scyint
88275970Scyevthread_set_lock_callbacks(const struct evthread_lock_callbacks *cbs)
89275970Scy{
90282408Scy	struct evthread_lock_callbacks *target = evthread_get_lock_callbacks();
91275970Scy
92275970Scy	if (!cbs) {
93275970Scy		if (target->alloc)
94275970Scy			event_warnx("Trying to disable lock functions after "
95275970Scy			    "they have been set up will probaby not work.");
96275970Scy		memset(target, 0, sizeof(evthread_lock_fns_));
97275970Scy		return 0;
98275970Scy	}
99275970Scy	if (target->alloc) {
100275970Scy		/* Uh oh; we already had locking callbacks set up.*/
101275970Scy		if (target->lock_api_version == cbs->lock_api_version &&
102275970Scy			target->supported_locktypes == cbs->supported_locktypes &&
103275970Scy			target->alloc == cbs->alloc &&
104275970Scy			target->free == cbs->free &&
105275970Scy			target->lock == cbs->lock &&
106275970Scy			target->unlock == cbs->unlock) {
107275970Scy			/* no change -- allow this. */
108275970Scy			return 0;
109275970Scy		}
110275970Scy		event_warnx("Can't change lock callbacks once they have been "
111275970Scy		    "initialized.");
112275970Scy		return -1;
113275970Scy	}
114275970Scy	if (cbs->alloc && cbs->free && cbs->lock && cbs->unlock) {
115275970Scy		memcpy(target, cbs, sizeof(evthread_lock_fns_));
116275970Scy		return event_global_setup_locks_(1);
117275970Scy	} else {
118275970Scy		return -1;
119275970Scy	}
120275970Scy}
121275970Scy
122275970Scyint
123275970Scyevthread_set_condition_callbacks(const struct evthread_condition_callbacks *cbs)
124275970Scy{
125282408Scy	struct evthread_condition_callbacks *target = evthread_get_condition_callbacks();
126275970Scy
127275970Scy	if (!cbs) {
128275970Scy		if (target->alloc_condition)
129275970Scy			event_warnx("Trying to disable condition functions "
130275970Scy			    "after they have been set up will probaby not "
131275970Scy			    "work.");
132275970Scy		memset(target, 0, sizeof(evthread_cond_fns_));
133275970Scy		return 0;
134275970Scy	}
135275970Scy	if (target->alloc_condition) {
136275970Scy		/* Uh oh; we already had condition callbacks set up.*/
137275970Scy		if (target->condition_api_version == cbs->condition_api_version &&
138275970Scy			target->alloc_condition == cbs->alloc_condition &&
139275970Scy			target->free_condition == cbs->free_condition &&
140275970Scy			target->signal_condition == cbs->signal_condition &&
141275970Scy			target->wait_condition == cbs->wait_condition) {
142275970Scy			/* no change -- allow this. */
143275970Scy			return 0;
144275970Scy		}
145275970Scy		event_warnx("Can't change condition callbacks once they "
146275970Scy		    "have been initialized.");
147275970Scy		return -1;
148275970Scy	}
149275970Scy	if (cbs->alloc_condition && cbs->free_condition &&
150275970Scy	    cbs->signal_condition && cbs->wait_condition) {
151275970Scy		memcpy(target, cbs, sizeof(evthread_cond_fns_));
152275970Scy	}
153275970Scy	if (evthread_lock_debugging_enabled_) {
154275970Scy		evthread_cond_fns_.alloc_condition = cbs->alloc_condition;
155275970Scy		evthread_cond_fns_.free_condition = cbs->free_condition;
156275970Scy		evthread_cond_fns_.signal_condition = cbs->signal_condition;
157275970Scy	}
158275970Scy	return 0;
159275970Scy}
160275970Scy
161275970Scy#define DEBUG_LOCK_SIG	0xdeb0b10c
162275970Scy
163275970Scystruct debug_lock {
164275970Scy	unsigned signature;
165275970Scy	unsigned locktype;
166275970Scy	unsigned long held_by;
167275970Scy	/* XXXX if we ever use read-write locks, we will need a separate
168275970Scy	 * lock to protect count. */
169275970Scy	int count;
170275970Scy	void *lock;
171275970Scy};
172275970Scy
173275970Scystatic void *
174275970Scydebug_lock_alloc(unsigned locktype)
175275970Scy{
176275970Scy	struct debug_lock *result = mm_malloc(sizeof(struct debug_lock));
177275970Scy	if (!result)
178275970Scy		return NULL;
179275970Scy	if (original_lock_fns_.alloc) {
180275970Scy		if (!(result->lock = original_lock_fns_.alloc(
181275970Scy				locktype|EVTHREAD_LOCKTYPE_RECURSIVE))) {
182275970Scy			mm_free(result);
183275970Scy			return NULL;
184275970Scy		}
185275970Scy	} else {
186275970Scy		result->lock = NULL;
187275970Scy	}
188275970Scy	result->signature = DEBUG_LOCK_SIG;
189275970Scy	result->locktype = locktype;
190275970Scy	result->count = 0;
191275970Scy	result->held_by = 0;
192275970Scy	return result;
193275970Scy}
194275970Scy
195275970Scystatic void
196275970Scydebug_lock_free(void *lock_, unsigned locktype)
197275970Scy{
198275970Scy	struct debug_lock *lock = lock_;
199275970Scy	EVUTIL_ASSERT(lock->count == 0);
200275970Scy	EVUTIL_ASSERT(locktype == lock->locktype);
201275970Scy	EVUTIL_ASSERT(DEBUG_LOCK_SIG == lock->signature);
202275970Scy	if (original_lock_fns_.free) {
203275970Scy		original_lock_fns_.free(lock->lock,
204275970Scy		    lock->locktype|EVTHREAD_LOCKTYPE_RECURSIVE);
205275970Scy	}
206275970Scy	lock->lock = NULL;
207275970Scy	lock->count = -100;
208275970Scy	lock->signature = 0x12300fda;
209275970Scy	mm_free(lock);
210275970Scy}
211275970Scy
212275970Scystatic void
213275970Scyevthread_debug_lock_mark_locked(unsigned mode, struct debug_lock *lock)
214275970Scy{
215275970Scy	EVUTIL_ASSERT(DEBUG_LOCK_SIG == lock->signature);
216275970Scy	++lock->count;
217275970Scy	if (!(lock->locktype & EVTHREAD_LOCKTYPE_RECURSIVE))
218275970Scy		EVUTIL_ASSERT(lock->count == 1);
219275970Scy	if (evthread_id_fn_) {
220275970Scy		unsigned long me;
221275970Scy		me = evthread_id_fn_();
222275970Scy		if (lock->count > 1)
223275970Scy			EVUTIL_ASSERT(lock->held_by == me);
224275970Scy		lock->held_by = me;
225275970Scy	}
226275970Scy}
227275970Scy
228275970Scystatic int
229275970Scydebug_lock_lock(unsigned mode, void *lock_)
230275970Scy{
231275970Scy	struct debug_lock *lock = lock_;
232275970Scy	int res = 0;
233275970Scy	if (lock->locktype & EVTHREAD_LOCKTYPE_READWRITE)
234275970Scy		EVUTIL_ASSERT(mode & (EVTHREAD_READ|EVTHREAD_WRITE));
235275970Scy	else
236275970Scy		EVUTIL_ASSERT((mode & (EVTHREAD_READ|EVTHREAD_WRITE)) == 0);
237275970Scy	if (original_lock_fns_.lock)
238275970Scy		res = original_lock_fns_.lock(mode, lock->lock);
239275970Scy	if (!res) {
240275970Scy		evthread_debug_lock_mark_locked(mode, lock);
241275970Scy	}
242275970Scy	return res;
243275970Scy}
244275970Scy
245275970Scystatic void
246275970Scyevthread_debug_lock_mark_unlocked(unsigned mode, struct debug_lock *lock)
247275970Scy{
248275970Scy	EVUTIL_ASSERT(DEBUG_LOCK_SIG == lock->signature);
249275970Scy	if (lock->locktype & EVTHREAD_LOCKTYPE_READWRITE)
250275970Scy		EVUTIL_ASSERT(mode & (EVTHREAD_READ|EVTHREAD_WRITE));
251275970Scy	else
252275970Scy		EVUTIL_ASSERT((mode & (EVTHREAD_READ|EVTHREAD_WRITE)) == 0);
253275970Scy	if (evthread_id_fn_) {
254275970Scy		unsigned long me;
255275970Scy		me = evthread_id_fn_();
256275970Scy		EVUTIL_ASSERT(lock->held_by == me);
257275970Scy		if (lock->count == 1)
258275970Scy			lock->held_by = 0;
259275970Scy	}
260275970Scy	--lock->count;
261275970Scy	EVUTIL_ASSERT(lock->count >= 0);
262275970Scy}
263275970Scy
264275970Scystatic int
265275970Scydebug_lock_unlock(unsigned mode, void *lock_)
266275970Scy{
267275970Scy	struct debug_lock *lock = lock_;
268275970Scy	int res = 0;
269275970Scy	evthread_debug_lock_mark_unlocked(mode, lock);
270275970Scy	if (original_lock_fns_.unlock)
271275970Scy		res = original_lock_fns_.unlock(mode, lock->lock);
272275970Scy	return res;
273275970Scy}
274275970Scy
275275970Scystatic int
276275970Scydebug_cond_wait(void *cond_, void *lock_, const struct timeval *tv)
277275970Scy{
278275970Scy	int r;
279275970Scy	struct debug_lock *lock = lock_;
280275970Scy	EVUTIL_ASSERT(lock);
281275970Scy	EVUTIL_ASSERT(DEBUG_LOCK_SIG == lock->signature);
282275970Scy	EVLOCK_ASSERT_LOCKED(lock_);
283275970Scy	evthread_debug_lock_mark_unlocked(0, lock);
284275970Scy	r = original_cond_fns_.wait_condition(cond_, lock->lock, tv);
285275970Scy	evthread_debug_lock_mark_locked(0, lock);
286275970Scy	return r;
287275970Scy}
288275970Scy
289275970Scy/* misspelled version for backward compatibility */
290275970Scyvoid
291275970Scyevthread_enable_lock_debuging(void)
292275970Scy{
293275970Scy	evthread_enable_lock_debugging();
294275970Scy}
295275970Scy
296275970Scyvoid
297275970Scyevthread_enable_lock_debugging(void)
298275970Scy{
299275970Scy	struct evthread_lock_callbacks cbs = {
300275970Scy		EVTHREAD_LOCK_API_VERSION,
301275970Scy		EVTHREAD_LOCKTYPE_RECURSIVE,
302275970Scy		debug_lock_alloc,
303275970Scy		debug_lock_free,
304275970Scy		debug_lock_lock,
305275970Scy		debug_lock_unlock
306275970Scy	};
307275970Scy	if (evthread_lock_debugging_enabled_)
308275970Scy		return;
309275970Scy	memcpy(&original_lock_fns_, &evthread_lock_fns_,
310275970Scy	    sizeof(struct evthread_lock_callbacks));
311275970Scy	memcpy(&evthread_lock_fns_, &cbs,
312275970Scy	    sizeof(struct evthread_lock_callbacks));
313275970Scy
314275970Scy	memcpy(&original_cond_fns_, &evthread_cond_fns_,
315275970Scy	    sizeof(struct evthread_condition_callbacks));
316275970Scy	evthread_cond_fns_.wait_condition = debug_cond_wait;
317275970Scy	evthread_lock_debugging_enabled_ = 1;
318275970Scy
319275970Scy	/* XXX return value should get checked. */
320275970Scy	event_global_setup_locks_(0);
321275970Scy}
322275970Scy
323275970Scyint
324275970Scyevthread_is_debug_lock_held_(void *lock_)
325275970Scy{
326275970Scy	struct debug_lock *lock = lock_;
327275970Scy	if (! lock->count)
328275970Scy		return 0;
329275970Scy	if (evthread_id_fn_) {
330275970Scy		unsigned long me = evthread_id_fn_();
331275970Scy		if (lock->held_by != me)
332275970Scy			return 0;
333275970Scy	}
334275970Scy	return 1;
335275970Scy}
336275970Scy
337275970Scyvoid *
338275970Scyevthread_debug_get_real_lock_(void *lock_)
339275970Scy{
340275970Scy	struct debug_lock *lock = lock_;
341275970Scy	return lock->lock;
342275970Scy}
343275970Scy
344275970Scyvoid *
345275970Scyevthread_setup_global_lock_(void *lock_, unsigned locktype, int enable_locks)
346275970Scy{
347275970Scy	/* there are four cases here:
348275970Scy	   1) we're turning on debugging; locking is not on.
349275970Scy	   2) we're turning on debugging; locking is on.
350275970Scy	   3) we're turning on locking; debugging is not on.
351275970Scy	   4) we're turning on locking; debugging is on. */
352275970Scy
353275970Scy	if (!enable_locks && original_lock_fns_.alloc == NULL) {
354275970Scy		/* Case 1: allocate a debug lock. */
355275970Scy		EVUTIL_ASSERT(lock_ == NULL);
356275970Scy		return debug_lock_alloc(locktype);
357275970Scy	} else if (!enable_locks && original_lock_fns_.alloc != NULL) {
358275970Scy		/* Case 2: wrap the lock in a debug lock. */
359275970Scy		struct debug_lock *lock;
360275970Scy		EVUTIL_ASSERT(lock_ != NULL);
361275970Scy
362275970Scy		if (!(locktype & EVTHREAD_LOCKTYPE_RECURSIVE)) {
363275970Scy			/* We can't wrap it: We need a recursive lock */
364275970Scy			original_lock_fns_.free(lock_, locktype);
365275970Scy			return debug_lock_alloc(locktype);
366275970Scy		}
367275970Scy		lock = mm_malloc(sizeof(struct debug_lock));
368275970Scy		if (!lock) {
369275970Scy			original_lock_fns_.free(lock_, locktype);
370275970Scy			return NULL;
371275970Scy		}
372275970Scy		lock->lock = lock_;
373275970Scy		lock->locktype = locktype;
374275970Scy		lock->count = 0;
375275970Scy		lock->held_by = 0;
376275970Scy		return lock;
377275970Scy	} else if (enable_locks && ! evthread_lock_debugging_enabled_) {
378275970Scy		/* Case 3: allocate a regular lock */
379275970Scy		EVUTIL_ASSERT(lock_ == NULL);
380275970Scy		return evthread_lock_fns_.alloc(locktype);
381275970Scy	} else {
382275970Scy		/* Case 4: Fill in a debug lock with a real lock */
383275970Scy		struct debug_lock *lock = lock_;
384275970Scy		EVUTIL_ASSERT(enable_locks &&
385275970Scy		              evthread_lock_debugging_enabled_);
386275970Scy		EVUTIL_ASSERT(lock->locktype == locktype);
387275970Scy		EVUTIL_ASSERT(lock->lock == NULL);
388275970Scy		lock->lock = original_lock_fns_.alloc(
389275970Scy			locktype|EVTHREAD_LOCKTYPE_RECURSIVE);
390275970Scy		if (!lock->lock) {
391275970Scy			lock->count = -200;
392275970Scy			mm_free(lock);
393275970Scy			return NULL;
394275970Scy		}
395275970Scy		return lock;
396275970Scy	}
397275970Scy}
398275970Scy
399275970Scy
400275970Scy#ifndef EVTHREAD_EXPOSE_STRUCTS
401275970Scyunsigned long
402275970Scyevthreadimpl_get_id_()
403275970Scy{
404275970Scy	return evthread_id_fn_ ? evthread_id_fn_() : 1;
405275970Scy}
406275970Scyvoid *
407275970Scyevthreadimpl_lock_alloc_(unsigned locktype)
408275970Scy{
409275970Scy	return evthread_lock_fns_.alloc ?
410275970Scy	    evthread_lock_fns_.alloc(locktype) : NULL;
411275970Scy}
412275970Scyvoid
413275970Scyevthreadimpl_lock_free_(void *lock, unsigned locktype)
414275970Scy{
415275970Scy	if (evthread_lock_fns_.free)
416275970Scy		evthread_lock_fns_.free(lock, locktype);
417275970Scy}
418275970Scyint
419275970Scyevthreadimpl_lock_lock_(unsigned mode, void *lock)
420275970Scy{
421275970Scy	if (evthread_lock_fns_.lock)
422275970Scy		return evthread_lock_fns_.lock(mode, lock);
423275970Scy	else
424275970Scy		return 0;
425275970Scy}
426275970Scyint
427275970Scyevthreadimpl_lock_unlock_(unsigned mode, void *lock)
428275970Scy{
429275970Scy	if (evthread_lock_fns_.unlock)
430275970Scy		return evthread_lock_fns_.unlock(mode, lock);
431275970Scy	else
432275970Scy		return 0;
433275970Scy}
434275970Scyvoid *
435275970Scyevthreadimpl_cond_alloc_(unsigned condtype)
436275970Scy{
437275970Scy	return evthread_cond_fns_.alloc_condition ?
438275970Scy	    evthread_cond_fns_.alloc_condition(condtype) : NULL;
439275970Scy}
440275970Scyvoid
441275970Scyevthreadimpl_cond_free_(void *cond)
442275970Scy{
443275970Scy	if (evthread_cond_fns_.free_condition)
444275970Scy		evthread_cond_fns_.free_condition(cond);
445275970Scy}
446275970Scyint
447275970Scyevthreadimpl_cond_signal_(void *cond, int broadcast)
448275970Scy{
449275970Scy	if (evthread_cond_fns_.signal_condition)
450275970Scy		return evthread_cond_fns_.signal_condition(cond, broadcast);
451275970Scy	else
452275970Scy		return 0;
453275970Scy}
454275970Scyint
455275970Scyevthreadimpl_cond_wait_(void *cond, void *lock, const struct timeval *tv)
456275970Scy{
457275970Scy	if (evthread_cond_fns_.wait_condition)
458275970Scy		return evthread_cond_fns_.wait_condition(cond, lock, tv);
459275970Scy	else
460275970Scy		return 0;
461275970Scy}
462275970Scyint
463275970Scyevthreadimpl_is_lock_debugging_enabled_(void)
464275970Scy{
465275970Scy	return evthread_lock_debugging_enabled_;
466275970Scy}
467275970Scy
468275970Scyint
469275970Scyevthreadimpl_locking_enabled_(void)
470275970Scy{
471275970Scy	return evthread_lock_fns_.lock != NULL;
472275970Scy}
473275970Scy#endif
474275970Scy
475275970Scy#endif
476