]> granicus.if.org Git - libevent/commitdiff
Add support for priority inheritance
authorAndre Pereira Azevedo Pinto <andrep@lyft.com>
Thu, 5 Dec 2019 01:56:54 +0000 (17:56 -0800)
committerAndre Pereira Azevedo Pinto <andrep@lyft.com>
Mon, 9 Dec 2019 22:55:31 +0000 (14:55 -0800)
Add support for posix mutex priority inheritance. This is important to
avoid priority inversion in systems running with threads with different
priorities.

Signed-off-by: Andre Azevedo <andre.azevedo@gmail.com>
evthread_pthread.c
include/event2/thread.h
test/regress.h
test/regress_main.c
test/regress_thread.c

index 4e11f74970ab633acdb3cf08ddb6330169244988..a40f5b02787b7bd83bfa2276dfccb0b5920f6bc4 100644 (file)
@@ -39,12 +39,13 @@ struct event_base;
 #include "mm-internal.h"
 #include "evthread-internal.h"
 
+static pthread_mutexattr_t attr_default;
 static pthread_mutexattr_t attr_recursive;
 
 static void *
 evthread_posix_lock_alloc(unsigned locktype)
 {
-       pthread_mutexattr_t *attr = NULL;
+       pthread_mutexattr_t *attr = &attr_default;
        pthread_mutex_t *lock = mm_malloc(sizeof(pthread_mutex_t));
        if (!lock)
                return NULL;
@@ -161,7 +162,7 @@ evthread_posix_cond_wait(void *cond_, void *lock_, const struct timeval *tv)
 }
 
 int
-evthread_use_pthreads(void)
+evthread_use_pthreads_with_flags(int flags)
 {
        struct evthread_lock_callbacks cbs = {
                EVTHREAD_LOCK_API_VERSION,
@@ -178,14 +179,32 @@ evthread_use_pthreads(void)
                evthread_posix_cond_signal,
                evthread_posix_cond_wait
        };
+
+       if (pthread_mutexattr_init(&attr_default))
+               return -1;
+
        /* Set ourselves up to get recursive locks. */
        if (pthread_mutexattr_init(&attr_recursive))
                return -1;
        if (pthread_mutexattr_settype(&attr_recursive, PTHREAD_MUTEX_RECURSIVE))
                return -1;
 
+       if (flags & EVTHREAD_PTHREAD_PRIO_INHERIT) {
+               /* Set up priority inheritance */
+               if (pthread_mutexattr_setprotocol(&attr_default, PTHREAD_PRIO_INHERIT))
+                       return -1;
+               if (pthread_mutexattr_setprotocol(&attr_recursive, PTHREAD_PRIO_INHERIT))
+                       return -1;
+       }
+
        evthread_set_lock_callbacks(&cbs);
        evthread_set_condition_callbacks(&cond_cbs);
        evthread_set_id_callback(evthread_posix_get_id);
        return 0;
 }
+
+int
+evthread_use_pthreads(void)
+{
+       return evthread_use_pthreads_with_flags(0);
+}
index fa1b09c01bf1567c34e6bfcf630bfaee2dc0d72b..bf06e3d3ebd38107b703e9ca5e62643f9edf5800 100644 (file)
@@ -212,6 +212,21 @@ int evthread_use_windows_threads(void);
     @return 0 on success, -1 on failure. */
 EVENT2_EXPORT_SYMBOL
 int evthread_use_pthreads(void);
+
+/* Enables posix mutex priority inheritance. */
+#define EVTHREAD_PTHREAD_PRIO_INHERIT 0x01
+
+/**
+ * Sets up Libevent for use with Pthreads locking and thread ID functions.
+ * Use evthred_use_pthreads_with_flags() to use Pthreads locking, taking the
+ * specified flags under consideration.
+ *
+ * @param flags the flags to apply when setting up Pthreads locking. @see EVTHREAD_PTHREAD_*
+ * @return 0 on success, -1 on failure.
+ **/
+EVENT2_EXPORT_SYMBOL
+int evthread_use_pthreads_with_flags(int flags);
+
 /** Defined if Libevent was built with support for evthread_use_pthreads() */
 #define EVTHREAD_USE_PTHREADS_IMPLEMENTED 1
 
index dad806648b0a676c4b4ebd8108371040688acd20..55a2fddb9ba573bbce7dfbc8429cf484b2769cbd 100644 (file)
@@ -97,6 +97,7 @@ extern int libevent_tests_running_in_debug_mode;
 #define TT_ENABLE_IOCP_FLAG    (TT_FIRST_USER_FLAG<<6)
 #define TT_ENABLE_IOCP         (TT_ENABLE_IOCP_FLAG|TT_NEED_THREADS)
 #define TT_ENABLE_DEBUG_MODE   (TT_ENABLE_IOCP_FLAG<<7)
+#define TT_ENABLE_PRIORITY_INHERITANCE (TT_ENABLE_IOCP_FLAG<<8)
 
 /* All the flags that a legacy test needs. */
 #define TT_ISOLATED TT_FORK|TT_NEED_SOCKETPAIR|TT_NEED_BASE
index c5bc1ae60c726654b856f435587403737189991e..1b6ede7ec367f2a8b55ed1b5e7c363133e12aac8 100644 (file)
@@ -193,6 +193,12 @@ basic_test_setup(const struct testcase_t *testcase)
        evutil_socket_t spair[2] = { -1, -1 };
        struct basic_test_data *data = NULL;
 
+#if defined(EVTHREAD_USE_PTHREADS_IMPLEMENTED)
+       int evthread_flags = 0;
+       if (testcase->flags & TT_ENABLE_PRIORITY_INHERITANCE)
+               evthread_flags |= EVTHREAD_PTHREAD_PRIO_INHERIT;
+#endif
+
 #ifndef _WIN32
        if (testcase->flags & TT_ENABLE_IOCP_FLAG)
                return (void*)TT_SKIP;
@@ -208,7 +214,7 @@ basic_test_setup(const struct testcase_t *testcase)
                if (!(testcase->flags & TT_FORK))
                        return NULL;
 #if defined(EVTHREAD_USE_PTHREADS_IMPLEMENTED)
-               if (evthread_use_pthreads())
+               if (evthread_use_pthreads_with_flags(evthread_flags))
                        exit(1);
 #elif defined(EVTHREAD_USE_WINDOWS_THREADS_IMPLEMENTED)
                if (evthread_use_windows_threads())
index 1e0ce41ff95e3afc40fb99eb1a2732816caa2cf1..3f46764d564164960bdb32fc88849cb2d4fac4dc 100644 (file)
@@ -574,6 +574,9 @@ struct testcase_t thread_testcases[] = {
 #ifndef _WIN32
        { "forking", thread_basic, TT_FORK|TT_NEED_THREADS|TT_NEED_BASE,
          &basic_setup, (char*)"forking" },
+       { "priority_inheritance", thread_basic,
+         TT_FORK|TT_NEED_THREADS|TT_NEED_BASE|TT_ENABLE_PRIORITY_INHERITANCE,
+         &basic_setup, (char*)"priority_inheritance" },
 #endif
        TEST(conditions_simple, TT_RETRIABLE),
        { "deferred_cb_skew", thread_deferred_cb_skew,