From dcfb19a27b7760299bc9e7291c9abd88c59fd91a Mon Sep 17 00:00:00 2001 From: Mark Ellzey Date: Fri, 15 May 2015 02:58:14 -0700 Subject: [PATCH] Debug mode option to error on evthread init AFTER other event calls. - A handy event_enable_debug_mode() feature which will error and abort the application if any thread-aware libevent functions are called BEFORE the evthread API has been initialized (manually, or through evthread_use_windows_threads() / evthread_use_pthreads() - This is done by setting the global debug variable 'event_debug_created_threadable_ctx_' whenever the following functions are called: evthreadimpl_lock_alloc_() evthreadimpl_cond_alloc_() event_base_new_with_config() <- this checks to see if the thread callbacks are enabled first, so we have to manually set the variable. - Example: int main(int argc, char ** argv) { struct event_base * base; event_enable_debug_mode(); base = event_base_new(); evthread_use_pthreads(); return 0; } When executed, the program will throw an error and exit: [err] evthread initialization must be called BEFORE anything else! --- event.c | 16 ++++++++++++++++ evthread.c | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/event.c b/event.c index acef2b24..a932c3bb 100644 --- a/event.c +++ b/event.c @@ -199,6 +199,20 @@ eq_debug_entry(const struct event_debug_entry *a, } int event_debug_mode_on_ = 0; + + +/** + * @brief debug mode variable which is set for any function/structure that needs + * to be shared across threads (if thread support is enabled). + * + * When and if evthreads are initialized, this variable will be evaluated, + * and if set to something other than zero, this means the evthread setup + * functions were called out of order. + * + * See: "Locks and threading" in the documentation. + */ +int event_debug_created_threadable_ctx_ = 0; + /* Set if it's too late to enable event_debug_mode. */ static int event_debug_mode_too_late = 0; #ifndef EVENT__DISABLE_THREAD_SUPPORT @@ -656,6 +670,8 @@ event_base_new_with_config(const struct event_config *cfg) /* prepare for threading */ #ifndef EVENT__DISABLE_THREAD_SUPPORT + event_debug_created_threadable_ctx_ = 1; + if (EVTHREAD_LOCKING_ENABLED() && (!cfg || !(cfg->flags & EVENT_BASE_FLAG_NOLOCK))) { int r; diff --git a/evthread.c b/evthread.c index 02dab7a8..b8c5fb63 100644 --- a/evthread.c +++ b/evthread.c @@ -45,6 +45,11 @@ #define GLOBAL static #endif +#ifndef EVENT__DISABLE_DEBUG_MODE +extern int event_debug_created_threadable_ctx_; +extern int event_debug_mode_on_; +#endif + /* globals */ GLOBAL int evthread_lock_debugging_enabled_ = 0; GLOBAL struct evthread_lock_callbacks evthread_lock_fns_ = { @@ -89,6 +94,14 @@ evthread_set_lock_callbacks(const struct evthread_lock_callbacks *cbs) { struct evthread_lock_callbacks *target = evthread_get_lock_callbacks(); +#ifndef EVENT__DISABLE_DEBUG_MODE + if (event_debug_mode_on_) { + if (event_debug_created_threadable_ctx_) { + event_errx(1, "evthread initialization must be called BEFORE anything else!"); + } + } +#endif + if (!cbs) { if (target->alloc) event_warnx("Trying to disable lock functions after " @@ -124,6 +137,14 @@ evthread_set_condition_callbacks(const struct evthread_condition_callbacks *cbs) { struct evthread_condition_callbacks *target = evthread_get_condition_callbacks(); +#ifndef EVENT__DISABLE_DEBUG_MODE + if (event_debug_mode_on_) { + if (event_debug_created_threadable_ctx_) { + event_errx(1, "evthread initialization must be called BEFORE anything else!"); + } + } +#endif + if (!cbs) { if (target->alloc_condition) event_warnx("Trying to disable condition functions " @@ -406,6 +427,12 @@ evthreadimpl_get_id_() void * evthreadimpl_lock_alloc_(unsigned locktype) { +#ifndef EVENT__DISABLE_DEBUG_MODE + if (event_debug_mode_on_) { + event_debug_created_threadable_ctx_ = 1; + } +#endif + return evthread_lock_fns_.alloc ? evthread_lock_fns_.alloc(locktype) : NULL; } @@ -434,6 +461,12 @@ evthreadimpl_lock_unlock_(unsigned mode, void *lock) void * evthreadimpl_cond_alloc_(unsigned condtype) { +#ifndef EVENT__DISABLE_DEBUG_MODE + if (event_debug_mode_on_) { + event_debug_created_threadable_ctx_ = 1; + } +#endif + return evthread_cond_fns_.alloc_condition ? evthread_cond_fns_.alloc_condition(condtype) : NULL; }