From d4977b52f07d61e215e5d5e98af2216719c06d16 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Tue, 17 Aug 2010 13:15:34 -0400 Subject: Add a condition variable backend, with implementations for pthreads and win32 The interface from the user's POV is similar to the locking implementation: either provide a structure full of function pointers, or just call evthread_use_*_threads() and everything will be okay. The internal interface is meant to vaguely resemble pthread_cond_*, which Windows people will better recognize as *ConditionVariable*. --- evthread-internal.h | 43 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 2 deletions(-) (limited to 'evthread-internal.h') diff --git a/evthread-internal.h b/evthread-internal.h index 2be7c7ac..d710939a 100644 --- a/evthread-internal.h +++ b/evthread-internal.h @@ -40,6 +40,7 @@ struct event_base; /* Global function pointers to lock-related functions. NULL if locking isn't enabled. */ extern struct evthread_lock_callbacks _evthread_lock_fns; +extern struct evthread_condition_callbacks _evthread_cond_fns; extern unsigned long (*_evthread_id_fn)(void); extern int _evthread_lock_debugging_enabled; @@ -126,6 +127,9 @@ extern int _evthread_lock_debugging_enabled; EVLOCK_UNLOCK((base)->lockvar, 0); \ } while (0) +int _evthread_is_debug_lock_held(void *lock); +void *_evthread_debug_get_real_lock(void *lock); + /** If lock debugging is enabled, and lock is non-null, assert that 'lock' is * locked and held by us. */ #define EVLOCK_ASSERT_LOCKED(lock) \ @@ -135,8 +139,6 @@ extern int _evthread_lock_debugging_enabled; } \ } while (0) -int _evthread_is_debug_lock_held(void *lock); - /** Try to grab the lock for 'lockvar' without blocking, and return 1 if we * manage to get it. */ static inline int EVLOCK_TRY_LOCK(void *lock); @@ -153,6 +155,35 @@ EVLOCK_TRY_LOCK(void *lock) } } +/** Allocate a new condition variable and store it in the void *, condvar */ +#define EVTHREAD_ALLOC_COND(condvar) \ + do { \ + (condvar) = _evthread_cond_fns.alloc_condition ? \ + _evthread_cond_fns.alloc_condition(0) : NULL; \ + } while (0) +/** Deallocate and free a condition variable in condvar */ +#define EVTHREAD_FREE_COND(cond) \ + do { \ + if (cond) \ + _evthread_cond_fns.free_condition((cond)); \ + } while (0) +/** Signal one thread waiting on cond */ +#define EVTHREAD_COND_SIGNAL(cond) \ + ( (cond) ? _evthread_cond_fns.signal_condition((cond), 0) : 0 ) +/** Signal all threads waiting on cond */ +#define EVTHREAD_COND_BROADCAST(cond) \ + ( (cond) ? _evthread_cond_fns.signal_condition((cond), 1) : 0 ) +/** Wait until the condition 'cond' is signalled. Must be called while + * holding 'lock'. The lock will be released until the condition is + * signalled, at which point it will be acquired again. Returns 0 for + * success, -1 for failure. */ +#define EVTHREAD_COND_WAIT(cond, lock) \ + ( (cond) ? _evthread_cond_fns.wait_condition((cond), (lock), NULL) : 0 ) +/** As EVTHREAD_COND_WAIT, but gives up after 'tv' has elapsed. Returns 1 + * on timeout. */ +#define EVTHREAD_COND_WAIT_TIMED(cond, lock, tv) \ + ( (cond) ? _evthread_cond_fns.wait_condition((cond), (lock), (tv)) : 0 ) + #else /* _EVENT_DISABLE_THREAD_SUPPORT */ #define EVTHREAD_GET_ID() 1 @@ -170,6 +201,14 @@ EVLOCK_TRY_LOCK(void *lock) #define EVLOCK_ASSERT_LOCKED(lock) _EVUTIL_NIL_STMT #define EVLOCK_TRY_LOCK(lock) 1 + +#define EVTHREAD_ALLOC_COND(condvar) _EVUTIL_NIL_STMT +#define EVTHREAD_FREE_COND(cond) _EVUTIL_NIL_STMT +#define EVTHREAD_COND_SIGNAL(cond) _EVUTIL_NIL_STMT +#define EVTHREAD_COND_BROADCAST(cond) _EVUTIL_NIL_STMT +#define EVTHREAD_COND_WAIT(cond, lock) _EVUTIL_NIL_STMT +#define EVTHREAD_COND_WAIT_TIMED(cond, lock, howlong) _EVUTIL_NIL_STMT + #endif #ifdef __cplusplus -- cgit v1.2.1