summaryrefslogtreecommitdiff
path: root/dbus/dbus-threads.c
diff options
context:
space:
mode:
authorSimon McVittie <simon.mcvittie@collabora.co.uk>2013-04-16 16:28:44 +0100
committerSimon McVittie <simon.mcvittie@collabora.co.uk>2013-06-17 17:00:00 +0100
commit2b3272c75ae48c93911bd6f656965cf77d6de3e8 (patch)
treec612839ca6bf80883028d7e39c7c894d8c56b900 /dbus/dbus-threads.c
parentc80c20af46c5f43dcbe672f2c6d8aec0e7f2bbd6 (diff)
downloaddbus-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.c28
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 ())
{