diff options
author | Simon McVittie <simon.mcvittie@collabora.co.uk> | 2013-04-16 16:28:44 +0100 |
---|---|---|
committer | Simon McVittie <simon.mcvittie@collabora.co.uk> | 2013-06-17 17:00:00 +0100 |
commit | 2b3272c75ae48c93911bd6f656965cf77d6de3e8 (patch) | |
tree | c612839ca6bf80883028d7e39c7c894d8c56b900 /dbus/dbus-threads.c | |
parent | c80c20af46c5f43dcbe672f2c6d8aec0e7f2bbd6 (diff) | |
download | dbus-2b3272c75ae48c93911bd6f656965cf77d6de3e8.tar.gz |
Make taking a global lock automatically initialize locking if needed
This lets them be thread-safe by default, at the cost that they can
now fail.
init_uninitialized_locks() and init_global_locks() must now both
reimplement the equivalent of _dbus_register_shutdown_func(), by using
_dbus_platform_rmutex_lock() on the same underlying mutex around a call
to _dbus_register_shutdown_func_unlocked().
This is because if they used the usual _DBUS_LOCK() API (as
_dbus_register_shutdown_func() does), it would automatically try to
initialize global locking, leading to infinite recursion.
Bug: https://bugs.freedesktop.org/show_bug.cgi?id=54972
Signed-off-by: Simon McVittie <simon.mcvittie@collabora.co.uk>
Reviewed-by: Alban Crequy <alban.crequy@collabora.co.uk>
Reviewed-by: Anas Nashif <anas.nashif@intel.com>
Diffstat (limited to 'dbus/dbus-threads.c')
-rw-r--r-- | dbus/dbus-threads.c | 28 |
1 files changed, 19 insertions, 9 deletions
diff --git a/dbus/dbus-threads.c b/dbus/dbus-threads.c index 297a7e4e..2c2a8166 100644 --- a/dbus/dbus-threads.c +++ b/dbus/dbus-threads.c @@ -366,10 +366,12 @@ shutdown_uninitialized_locks (void *data) _dbus_list_clear (&uninitialized_condvar_list); } +/* init_global_locks() must be called first. */ static dbus_bool_t init_uninitialized_locks (void) { DBusList *link; + dbus_bool_t ok; _dbus_assert (thread_init_generation != _dbus_current_generation); @@ -422,8 +424,12 @@ init_uninitialized_locks (void) _dbus_list_clear (&uninitialized_cmutex_list); _dbus_list_clear (&uninitialized_condvar_list); - if (!_dbus_register_shutdown_func (shutdown_uninitialized_locks, - NULL)) + /* This assumes that init_global_locks() has already been called. */ + _dbus_platform_rmutex_lock (global_locks[_DBUS_LOCK_shutdown_funcs]); + ok = _dbus_register_shutdown_func_unlocked (shutdown_uninitialized_locks, NULL); + _dbus_platform_rmutex_unlock (global_locks[_DBUS_LOCK_shutdown_funcs]); + + if (!ok) goto fail_condvar; return TRUE; @@ -494,9 +500,9 @@ init_global_locks (void) goto failed; } - _dbus_lock (_DBUS_LOCK_NAME (shutdown_funcs)); + _dbus_platform_rmutex_lock (global_locks[_DBUS_LOCK_shutdown_funcs]); ok = _dbus_register_shutdown_func_unlocked (shutdown_global_locks, NULL); - _dbus_unlock (_DBUS_LOCK_NAME (shutdown_funcs)); + _dbus_platform_rmutex_unlock (global_locks[_DBUS_LOCK_shutdown_funcs]); if (!ok) goto failed; @@ -513,14 +519,18 @@ init_global_locks (void) return FALSE; } -void +dbus_bool_t _dbus_lock (DBusGlobalLock lock) { _dbus_assert (lock >= 0); _dbus_assert (lock < _DBUS_N_GLOBAL_LOCKS); - if (thread_init_generation == _dbus_current_generation) - _dbus_platform_rmutex_lock (global_locks[lock]); + if (thread_init_generation != _dbus_current_generation && + !dbus_threads_init_default ()) + return FALSE; + + _dbus_platform_rmutex_lock (global_locks[lock]); + return TRUE; } void @@ -529,8 +539,7 @@ _dbus_unlock (DBusGlobalLock lock) _dbus_assert (lock >= 0); _dbus_assert (lock < _DBUS_N_GLOBAL_LOCKS); - if (thread_init_generation == _dbus_current_generation) - _dbus_platform_rmutex_unlock (global_locks[lock]); + _dbus_platform_rmutex_unlock (global_locks[lock]); } /** @} */ /* end of internals */ @@ -576,6 +585,7 @@ dbus_threads_init (const DBusThreadFunctions *functions) } if (!_dbus_threads_init_platform_specific() || + /* init_global_locks() must be called before init_uninitialized_locks. */ !init_global_locks () || !init_uninitialized_locks ()) { |