From c7accf24b8deb0b7edb5ceb38f783a202d5d1787 Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Mon, 15 Apr 2013 17:05:48 +0100 Subject: [PATCH 3/8] dbus_threads_init_default, dbus_threads_init: be thread-safe on Unix This means that libraries that will only be used on Unix can safely call them before they call into libdbus, in the knowledge that if everyone does the same, libdbus will be thread-safe. Until someone helps to implement and test this functionality on Windows, the same cannot be said for Windows, but it's better than nothing... --- dbus/dbus-memory.c | 7 +++++++ dbus/dbus-sysdeps-pthread.c | 14 ++++++++++++++ dbus/dbus-sysdeps-thread-win.c | 13 +++++++++++++ dbus/dbus-sysdeps.h | 12 ++++++++++++ dbus/dbus-threads.c | 28 +++++++++++++++++++++------- 5 files changed, 67 insertions(+), 7 deletions(-) diff --git a/dbus/dbus-memory.c b/dbus/dbus-memory.c index a033b54..317e37e 100644 --- a/dbus/dbus-memory.c +++ b/dbus/dbus-memory.c @@ -26,6 +26,7 @@ #include "dbus-internals.h" #include "dbus-sysdeps.h" #include "dbus-list.h" +#include "dbus-threads.h" #include /** @@ -890,7 +891,13 @@ dbus_shutdown (void) dbus_free (c); } + /* We wrap this in the thread-initialization lock because + * dbus_threads_init() uses the current generation to tell whether + * we're initialized, so we need to make sure that un-initializing + * propagates into all threads. */ + _dbus_threads_lock_platform_specific (); _dbus_current_generation += 1; + _dbus_threads_unlock_platform_specific (); } /** @} */ /** End of public API docs block */ diff --git a/dbus/dbus-sysdeps-pthread.c b/dbus/dbus-sysdeps-pthread.c index 1344074..1300ec3 100644 --- a/dbus/dbus-sysdeps-pthread.c +++ b/dbus/dbus-sysdeps-pthread.c @@ -286,3 +286,17 @@ _dbus_threads_init_platform_specific (void) return TRUE; } + +static pthread_mutex_t init_mutex = PTHREAD_MUTEX_INITIALIZER; + +void +_dbus_threads_lock_platform_specific (void) +{ + pthread_mutex_lock (&init_mutex); +} + +void +_dbus_threads_unlock_platform_specific (void) +{ + pthread_mutex_unlock (&init_mutex); +} diff --git a/dbus/dbus-sysdeps-thread-win.c b/dbus/dbus-sysdeps-thread-win.c index 4c4442a..5cf0cf8 100644 --- a/dbus/dbus-sysdeps-thread-win.c +++ b/dbus/dbus-sysdeps-thread-win.c @@ -272,3 +272,16 @@ _dbus_threads_init_platform_specific (void) return TRUE; } +void +_dbus_threads_lock_platform_specific (void) +{ + /* FIXME: take a process-global lock here; then we can change all the + * "On Unix... On Windows..." in dbus-threads.c to just the thread-safe + * (currently Unix) case. */ +} + +void +_dbus_threads_unlock_platform_specific (void) +{ + /* FIXME: release the global lock here */ +} diff --git a/dbus/dbus-sysdeps.h b/dbus/dbus-sysdeps.h index a3205cf..d92325c 100644 --- a/dbus/dbus-sysdeps.h +++ b/dbus/dbus-sysdeps.h @@ -520,6 +520,18 @@ dbus_bool_t _dbus_read_local_machine_uuid (DBusGUID *machine_id, */ dbus_bool_t _dbus_threads_init_platform_specific (void); +/** + * Lock a static mutex used to protect _dbus_threads_init_platform_specific(). + * + * On Windows, this is currently unimplemented and does nothing. + */ +void _dbus_threads_lock_platform_specific (void); + +/** + * Undo _dbus_threads_lock_platform_specific(). + */ +void _dbus_threads_unlock_platform_specific (void); + dbus_bool_t _dbus_split_paths_and_append (DBusString *dirs, const char *suffix, DBusList **dir_list); diff --git a/dbus/dbus-threads.c b/dbus/dbus-threads.c index e7f2eb7..ddd83cb 100644 --- a/dbus/dbus-threads.c +++ b/dbus/dbus-threads.c @@ -581,15 +581,24 @@ init_locks (void) dbus_bool_t dbus_threads_init (const DBusThreadFunctions *functions) { + _dbus_threads_lock_platform_specific (); + if (thread_init_generation == _dbus_current_generation) - return TRUE; + { + _dbus_threads_unlock_platform_specific (); + return TRUE; + } if (!_dbus_threads_init_platform_specific() || !init_locks ()) - return FALSE; + { + _dbus_threads_unlock_platform_specific (); + return FALSE; + } thread_init_generation = _dbus_current_generation; - + + _dbus_threads_unlock_platform_specific (); return TRUE; } @@ -600,11 +609,16 @@ dbus_threads_init (const DBusThreadFunctions *functions) /** * Initializes threads. If this function is not called, the D-Bus * library will not lock any data structures. If it is called, D-Bus - * will do locking, at some cost in efficiency. Note that this - * function must be called BEFORE the second thread is started. + * will do locking, at some cost in efficiency. + * + * On Unix platforms, since D-Bus 1.7 it is safe to call this function + * from any thread, any number of times (but it must be called before + * any other libdbus API is used). * - * It's safe to call dbus_threads_init_default() as many times as you - * want, but only the first time will have an effect. + * On Windows, and in D-Bus 1.6 or older, this function must be called in + * the main thread before any other thread starts. As a result, it is not + * sufficient to call this function in a library or plugin, unless the + * library or plugin imposes a similar requirement on its callers. * * dbus_shutdown() reverses the effects of this function when it * resets all global state in libdbus. -- 1.7.10.4