]> granicus.if.org Git - libevent/commitdiff
Debug mode option to error on evthread init AFTER other event calls.
authorMark Ellzey <socket@gmail.com>
Fri, 15 May 2015 09:58:14 +0000 (02:58 -0700)
committerMark Ellzey <socket@gmail.com>
Fri, 15 May 2015 09:58:14 +0000 (02:58 -0700)
- 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
evthread.c

diff --git a/event.c b/event.c
index acef2b2455cd85ed65e7a2dfaa16d0673c09ec29..a932c3bbbc8c65c86fd8884cf77e03a839ebfdb8 100644 (file)
--- 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;
index 02dab7a8057e58f0fe64b0175ed016635d442eec..b8c5fb635c41925bd496ef50c9cfc794de99069c 100644 (file)
 #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;
 }