mirror of
https://gitlab.freedesktop.org/dbus/dbus.git
synced 2026-01-06 08:20:13 +01:00
Distinguish between two flavours of mutex
dbus-threads.h warns that recursive pthreads mutexes are not compatible with our expectations for condition variables. However, the only two condition variables we actually use only have their corresponding mutexes locked briefly (and we don't call out to user code from there), so the mutexes don't need to be recursive anyway. That's just as well, because it turns out our implementation of recursive mutexes on pthreads is broken! The goal here is to be able to distinguish between "cmutexes" (mutexes compatible with a condition variable) and "rmutexes" (mutexes which are recursive if possible, to avoid deadlocking if we hold them while calling user code). This is complicated by the fact that callers are not guaranteed to have provided us with both versions of mutexes, so we might have to implement one by using the other (in particular, DBusRMutex *aims to be* recursive, it is not *guaranteed to be* recursive). Bug: https://bugs.freedesktop.org/show_bug.cgi?id=43744 Signed-off-by: Simon McVittie <simon.mcvittie@collabora.co.uk> Reviewed-by: Thiago Macieira <thiago@kde.org>
This commit is contained in:
parent
4d4da20ce7
commit
8a58250acf
8 changed files with 285 additions and 116 deletions
|
|
@ -66,18 +66,18 @@
|
|||
|
||||
#define CONNECTION_LOCK(connection) do { \
|
||||
if (TRACE_LOCKS) { _dbus_verbose ("LOCK\n"); } \
|
||||
_dbus_mutex_lock ((connection)->mutex); \
|
||||
_dbus_rmutex_lock ((connection)->mutex); \
|
||||
TOOK_LOCK_CHECK (connection); \
|
||||
} while (0)
|
||||
|
||||
#define CONNECTION_UNLOCK(connection) _dbus_connection_unlock (connection)
|
||||
|
||||
#define SLOTS_LOCK(connection) do { \
|
||||
_dbus_mutex_lock ((connection)->slot_mutex); \
|
||||
_dbus_rmutex_lock ((connection)->slot_mutex); \
|
||||
} while (0)
|
||||
|
||||
#define SLOTS_UNLOCK(connection) do { \
|
||||
_dbus_mutex_unlock ((connection)->slot_mutex); \
|
||||
_dbus_rmutex_unlock ((connection)->slot_mutex); \
|
||||
} while (0)
|
||||
|
||||
#define DISPATCH_STATUS_NAME(s) \
|
||||
|
|
@ -264,11 +264,11 @@ struct DBusConnection
|
|||
{
|
||||
DBusAtomic refcount; /**< Reference count. */
|
||||
|
||||
DBusMutex *mutex; /**< Lock on the entire DBusConnection */
|
||||
DBusRMutex *mutex; /**< Lock on the entire DBusConnection */
|
||||
|
||||
DBusMutex *dispatch_mutex; /**< Protects dispatch_acquired */
|
||||
DBusCMutex *dispatch_mutex; /**< Protects dispatch_acquired */
|
||||
DBusCondVar *dispatch_cond; /**< Notify when dispatch_acquired is available */
|
||||
DBusMutex *io_path_mutex; /**< Protects io_path_acquired */
|
||||
DBusCMutex *io_path_mutex; /**< Protects io_path_acquired */
|
||||
DBusCondVar *io_path_cond; /**< Notify when io_path_acquired is available */
|
||||
|
||||
DBusList *outgoing_messages; /**< Queue of messages we need to send, send the end of the list first. */
|
||||
|
|
@ -290,7 +290,7 @@ struct DBusConnection
|
|||
|
||||
DBusList *filter_list; /**< List of filters. */
|
||||
|
||||
DBusMutex *slot_mutex; /**< Lock on slot_list so overall connection lock need not be taken */
|
||||
DBusRMutex *slot_mutex; /**< Lock on slot_list so overall connection lock need not be taken */
|
||||
DBusDataSlotList slot_list; /**< Data stored by allocated integer ID */
|
||||
|
||||
DBusHashTable *pending_replies; /**< Hash of message serials to #DBusPendingCall. */
|
||||
|
|
@ -419,7 +419,7 @@ _dbus_connection_unlock (DBusConnection *connection)
|
|||
connection->expired_messages = NULL;
|
||||
|
||||
RELEASING_LOCK_CHECK (connection);
|
||||
_dbus_mutex_unlock (connection->mutex);
|
||||
_dbus_rmutex_unlock (connection->mutex);
|
||||
|
||||
for (iter = _dbus_list_pop_first_link (&expired_messages);
|
||||
iter != NULL;
|
||||
|
|
@ -467,9 +467,9 @@ _dbus_connection_test_get_locks (DBusConnection *connection,
|
|||
DBusCondVar **dispatch_cond_loc,
|
||||
DBusCondVar **io_path_cond_loc)
|
||||
{
|
||||
*mutex_loc = connection->mutex;
|
||||
*dispatch_mutex_loc = connection->dispatch_mutex;
|
||||
*io_path_mutex_loc = connection->io_path_mutex;
|
||||
*mutex_loc = (DBusMutex *) connection->mutex;
|
||||
*dispatch_mutex_loc = (DBusMutex *) connection->dispatch_mutex;
|
||||
*io_path_mutex_loc = (DBusMutex *) connection->io_path_mutex;
|
||||
*dispatch_cond_loc = connection->dispatch_cond;
|
||||
*io_path_cond_loc = connection->io_path_cond;
|
||||
}
|
||||
|
|
@ -1079,7 +1079,7 @@ _dbus_connection_acquire_io_path (DBusConnection *connection,
|
|||
CONNECTION_UNLOCK (connection);
|
||||
|
||||
_dbus_verbose ("locking io_path_mutex\n");
|
||||
_dbus_mutex_lock (connection->io_path_mutex);
|
||||
_dbus_cmutex_lock (connection->io_path_mutex);
|
||||
|
||||
_dbus_verbose ("start connection->io_path_acquired = %d timeout = %d\n",
|
||||
connection->io_path_acquired, timeout_milliseconds);
|
||||
|
|
@ -1128,7 +1128,7 @@ _dbus_connection_acquire_io_path (DBusConnection *connection,
|
|||
connection->io_path_acquired, we_acquired);
|
||||
|
||||
_dbus_verbose ("unlocking io_path_mutex\n");
|
||||
_dbus_mutex_unlock (connection->io_path_mutex);
|
||||
_dbus_cmutex_unlock (connection->io_path_mutex);
|
||||
|
||||
CONNECTION_LOCK (connection);
|
||||
|
||||
|
|
@ -1152,7 +1152,7 @@ _dbus_connection_release_io_path (DBusConnection *connection)
|
|||
HAVE_LOCK_CHECK (connection);
|
||||
|
||||
_dbus_verbose ("locking io_path_mutex\n");
|
||||
_dbus_mutex_lock (connection->io_path_mutex);
|
||||
_dbus_cmutex_lock (connection->io_path_mutex);
|
||||
|
||||
_dbus_assert (connection->io_path_acquired);
|
||||
|
||||
|
|
@ -1163,7 +1163,7 @@ _dbus_connection_release_io_path (DBusConnection *connection)
|
|||
_dbus_condvar_wake_one (connection->io_path_cond);
|
||||
|
||||
_dbus_verbose ("unlocking io_path_mutex\n");
|
||||
_dbus_mutex_unlock (connection->io_path_mutex);
|
||||
_dbus_cmutex_unlock (connection->io_path_mutex);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1292,15 +1292,15 @@ _dbus_connection_new_for_transport (DBusTransport *transport)
|
|||
if (connection == NULL)
|
||||
goto error;
|
||||
|
||||
_dbus_mutex_new_at_location (&connection->mutex);
|
||||
_dbus_rmutex_new_at_location (&connection->mutex);
|
||||
if (connection->mutex == NULL)
|
||||
goto error;
|
||||
|
||||
_dbus_mutex_new_at_location (&connection->io_path_mutex);
|
||||
_dbus_cmutex_new_at_location (&connection->io_path_mutex);
|
||||
if (connection->io_path_mutex == NULL)
|
||||
goto error;
|
||||
|
||||
_dbus_mutex_new_at_location (&connection->dispatch_mutex);
|
||||
_dbus_cmutex_new_at_location (&connection->dispatch_mutex);
|
||||
if (connection->dispatch_mutex == NULL)
|
||||
goto error;
|
||||
|
||||
|
|
@ -1312,7 +1312,7 @@ _dbus_connection_new_for_transport (DBusTransport *transport)
|
|||
if (connection->io_path_cond == NULL)
|
||||
goto error;
|
||||
|
||||
_dbus_mutex_new_at_location (&connection->slot_mutex);
|
||||
_dbus_rmutex_new_at_location (&connection->slot_mutex);
|
||||
if (connection->slot_mutex == NULL)
|
||||
goto error;
|
||||
|
||||
|
|
@ -1391,10 +1391,10 @@ _dbus_connection_new_for_transport (DBusTransport *transport)
|
|||
{
|
||||
_dbus_condvar_free_at_location (&connection->io_path_cond);
|
||||
_dbus_condvar_free_at_location (&connection->dispatch_cond);
|
||||
_dbus_mutex_free_at_location (&connection->mutex);
|
||||
_dbus_mutex_free_at_location (&connection->io_path_mutex);
|
||||
_dbus_mutex_free_at_location (&connection->dispatch_mutex);
|
||||
_dbus_mutex_free_at_location (&connection->slot_mutex);
|
||||
_dbus_rmutex_free_at_location (&connection->mutex);
|
||||
_dbus_cmutex_free_at_location (&connection->io_path_mutex);
|
||||
_dbus_cmutex_free_at_location (&connection->dispatch_mutex);
|
||||
_dbus_rmutex_free_at_location (&connection->slot_mutex);
|
||||
dbus_free (connection);
|
||||
}
|
||||
if (pending_replies)
|
||||
|
|
@ -2739,12 +2739,12 @@ _dbus_connection_last_unref (DBusConnection *connection)
|
|||
_dbus_condvar_free_at_location (&connection->dispatch_cond);
|
||||
_dbus_condvar_free_at_location (&connection->io_path_cond);
|
||||
|
||||
_dbus_mutex_free_at_location (&connection->io_path_mutex);
|
||||
_dbus_mutex_free_at_location (&connection->dispatch_mutex);
|
||||
_dbus_cmutex_free_at_location (&connection->io_path_mutex);
|
||||
_dbus_cmutex_free_at_location (&connection->dispatch_mutex);
|
||||
|
||||
_dbus_mutex_free_at_location (&connection->slot_mutex);
|
||||
_dbus_rmutex_free_at_location (&connection->slot_mutex);
|
||||
|
||||
_dbus_mutex_free_at_location (&connection->mutex);
|
||||
_dbus_rmutex_free_at_location (&connection->mutex);
|
||||
|
||||
dbus_free (connection);
|
||||
}
|
||||
|
|
@ -4088,7 +4088,7 @@ _dbus_connection_acquire_dispatch (DBusConnection *connection)
|
|||
CONNECTION_UNLOCK (connection);
|
||||
|
||||
_dbus_verbose ("locking dispatch_mutex\n");
|
||||
_dbus_mutex_lock (connection->dispatch_mutex);
|
||||
_dbus_cmutex_lock (connection->dispatch_mutex);
|
||||
|
||||
while (connection->dispatch_acquired)
|
||||
{
|
||||
|
|
@ -4102,7 +4102,7 @@ _dbus_connection_acquire_dispatch (DBusConnection *connection)
|
|||
connection->dispatch_acquired = TRUE;
|
||||
|
||||
_dbus_verbose ("unlocking dispatch_mutex\n");
|
||||
_dbus_mutex_unlock (connection->dispatch_mutex);
|
||||
_dbus_cmutex_unlock (connection->dispatch_mutex);
|
||||
|
||||
CONNECTION_LOCK (connection);
|
||||
_dbus_connection_unref_unlocked (connection);
|
||||
|
|
@ -4121,7 +4121,7 @@ _dbus_connection_release_dispatch (DBusConnection *connection)
|
|||
HAVE_LOCK_CHECK (connection);
|
||||
|
||||
_dbus_verbose ("locking dispatch_mutex\n");
|
||||
_dbus_mutex_lock (connection->dispatch_mutex);
|
||||
_dbus_cmutex_lock (connection->dispatch_mutex);
|
||||
|
||||
_dbus_assert (connection->dispatch_acquired);
|
||||
|
||||
|
|
@ -4129,7 +4129,7 @@ _dbus_connection_release_dispatch (DBusConnection *connection)
|
|||
_dbus_condvar_wake_one (connection->dispatch_cond);
|
||||
|
||||
_dbus_verbose ("unlocking dispatch_mutex\n");
|
||||
_dbus_mutex_unlock (connection->dispatch_mutex);
|
||||
_dbus_cmutex_unlock (connection->dispatch_mutex);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
|||
|
|
@ -67,12 +67,12 @@ _dbus_data_slot_allocator_init (DBusDataSlotAllocator *allocator)
|
|||
*/
|
||||
dbus_bool_t
|
||||
_dbus_data_slot_allocator_alloc (DBusDataSlotAllocator *allocator,
|
||||
DBusMutex **mutex_loc,
|
||||
DBusRMutex **mutex_loc,
|
||||
dbus_int32_t *slot_id_p)
|
||||
{
|
||||
dbus_int32_t slot;
|
||||
|
||||
_dbus_mutex_lock (*mutex_loc);
|
||||
_dbus_rmutex_lock (*mutex_loc);
|
||||
|
||||
if (allocator->n_allocated_slots == 0)
|
||||
{
|
||||
|
|
@ -146,7 +146,7 @@ _dbus_data_slot_allocator_alloc (DBusDataSlotAllocator *allocator,
|
|||
slot, allocator, allocator->n_allocated_slots, allocator->n_used_slots);
|
||||
|
||||
out:
|
||||
_dbus_mutex_unlock (*(allocator->lock_loc));
|
||||
_dbus_rmutex_unlock (*(allocator->lock_loc));
|
||||
return slot >= 0;
|
||||
}
|
||||
|
||||
|
|
@ -165,7 +165,7 @@ void
|
|||
_dbus_data_slot_allocator_free (DBusDataSlotAllocator *allocator,
|
||||
dbus_int32_t *slot_id_p)
|
||||
{
|
||||
_dbus_mutex_lock (*(allocator->lock_loc));
|
||||
_dbus_rmutex_lock (*(allocator->lock_loc));
|
||||
|
||||
_dbus_assert (*slot_id_p < allocator->n_allocated_slots);
|
||||
_dbus_assert (allocator->allocated_slots[*slot_id_p].slot_id == *slot_id_p);
|
||||
|
|
@ -175,7 +175,7 @@ _dbus_data_slot_allocator_free (DBusDataSlotAllocator *allocator,
|
|||
|
||||
if (allocator->allocated_slots[*slot_id_p].refcount > 0)
|
||||
{
|
||||
_dbus_mutex_unlock (*(allocator->lock_loc));
|
||||
_dbus_rmutex_unlock (*(allocator->lock_loc));
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -190,18 +190,18 @@ _dbus_data_slot_allocator_free (DBusDataSlotAllocator *allocator,
|
|||
|
||||
if (allocator->n_used_slots == 0)
|
||||
{
|
||||
DBusMutex **mutex_loc = allocator->lock_loc;
|
||||
DBusRMutex **mutex_loc = allocator->lock_loc;
|
||||
|
||||
dbus_free (allocator->allocated_slots);
|
||||
allocator->allocated_slots = NULL;
|
||||
allocator->n_allocated_slots = 0;
|
||||
allocator->lock_loc = NULL;
|
||||
|
||||
_dbus_mutex_unlock (*mutex_loc);
|
||||
_dbus_rmutex_unlock (*mutex_loc);
|
||||
}
|
||||
else
|
||||
{
|
||||
_dbus_mutex_unlock (*(allocator->lock_loc));
|
||||
_dbus_rmutex_unlock (*(allocator->lock_loc));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -247,10 +247,10 @@ _dbus_data_slot_list_set (DBusDataSlotAllocator *allocator,
|
|||
* be e.g. realloc()ing allocated_slots. We avoid doing this if asserts
|
||||
* are disabled, since then the asserts are empty.
|
||||
*/
|
||||
_dbus_mutex_lock (*(allocator->lock_loc));
|
||||
_dbus_rmutex_lock (*(allocator->lock_loc));
|
||||
_dbus_assert (slot < allocator->n_allocated_slots);
|
||||
_dbus_assert (allocator->allocated_slots[slot].slot_id == slot);
|
||||
_dbus_mutex_unlock (*(allocator->lock_loc));
|
||||
_dbus_rmutex_unlock (*(allocator->lock_loc));
|
||||
#endif
|
||||
|
||||
if (slot >= list->n_slots)
|
||||
|
|
@ -304,11 +304,11 @@ _dbus_data_slot_list_get (DBusDataSlotAllocator *allocator,
|
|||
* be e.g. realloc()ing allocated_slots. We avoid doing this if asserts
|
||||
* are disabled, since then the asserts are empty.
|
||||
*/
|
||||
_dbus_mutex_lock (*(allocator->lock_loc));
|
||||
_dbus_rmutex_lock (*(allocator->lock_loc));
|
||||
_dbus_assert (slot >= 0);
|
||||
_dbus_assert (slot < allocator->n_allocated_slots);
|
||||
_dbus_assert (allocator->allocated_slots[slot].slot_id == slot);
|
||||
_dbus_mutex_unlock (*(allocator->lock_loc));
|
||||
_dbus_rmutex_unlock (*(allocator->lock_loc));
|
||||
#endif
|
||||
|
||||
if (slot >= list->n_slots)
|
||||
|
|
@ -384,14 +384,14 @@ _dbus_data_slot_test (void)
|
|||
int i;
|
||||
DBusFreeFunction old_free_func;
|
||||
void *old_data;
|
||||
DBusMutex *mutex;
|
||||
DBusRMutex *mutex;
|
||||
|
||||
if (!_dbus_data_slot_allocator_init (&allocator))
|
||||
_dbus_assert_not_reached ("no memory for allocator");
|
||||
|
||||
_dbus_data_slot_list_init (&list);
|
||||
|
||||
_dbus_mutex_new_at_location (&mutex);
|
||||
_dbus_rmutex_new_at_location (&mutex);
|
||||
if (mutex == NULL)
|
||||
_dbus_assert_not_reached ("failed to alloc mutex");
|
||||
|
||||
|
|
@ -471,7 +471,7 @@ _dbus_data_slot_test (void)
|
|||
++i;
|
||||
}
|
||||
|
||||
_dbus_mutex_free_at_location (&mutex);
|
||||
_dbus_rmutex_free_at_location (&mutex);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ struct DBusDataSlotAllocator
|
|||
DBusAllocatedSlot *allocated_slots; /**< Allocated slots */
|
||||
int n_allocated_slots; /**< number of slots malloc'd */
|
||||
int n_used_slots; /**< number of slots used */
|
||||
DBusMutex **lock_loc; /**< location of thread lock */
|
||||
DBusRMutex **lock_loc; /**< location of thread lock */
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -72,7 +72,7 @@ struct DBusDataSlotList
|
|||
|
||||
dbus_bool_t _dbus_data_slot_allocator_init (DBusDataSlotAllocator *allocator);
|
||||
dbus_bool_t _dbus_data_slot_allocator_alloc (DBusDataSlotAllocator *allocator,
|
||||
DBusMutex **mutex_loc,
|
||||
DBusRMutex **mutex_loc,
|
||||
int *slot_id_p);
|
||||
void _dbus_data_slot_allocator_free (DBusDataSlotAllocator *allocator,
|
||||
int *slot_id_p);
|
||||
|
|
|
|||
|
|
@ -304,10 +304,10 @@ extern int _dbus_current_generation;
|
|||
|
||||
/* Thread initializers */
|
||||
#define _DBUS_LOCK_NAME(name) _dbus_lock_##name
|
||||
#define _DBUS_DECLARE_GLOBAL_LOCK(name) extern DBusMutex *_dbus_lock_##name
|
||||
#define _DBUS_DEFINE_GLOBAL_LOCK(name) DBusMutex *_dbus_lock_##name
|
||||
#define _DBUS_LOCK(name) _dbus_mutex_lock (_dbus_lock_##name)
|
||||
#define _DBUS_UNLOCK(name) _dbus_mutex_unlock (_dbus_lock_##name)
|
||||
#define _DBUS_DECLARE_GLOBAL_LOCK(name) extern DBusRMutex *_dbus_lock_##name
|
||||
#define _DBUS_DEFINE_GLOBAL_LOCK(name) DBusRMutex *_dbus_lock_##name
|
||||
#define _DBUS_LOCK(name) _dbus_rmutex_lock (_dbus_lock_##name)
|
||||
#define _DBUS_UNLOCK(name) _dbus_rmutex_unlock (_dbus_lock_##name)
|
||||
|
||||
/* 1-5 */
|
||||
_DBUS_DECLARE_GLOBAL_LOCK (list);
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ struct DBusServer
|
|||
{
|
||||
DBusAtomic refcount; /**< Reference count. */
|
||||
const DBusServerVTable *vtable; /**< Virtual methods for this instance. */
|
||||
DBusMutex *mutex; /**< Lock on the server object */
|
||||
DBusRMutex *mutex; /**< Lock on the server object */
|
||||
|
||||
DBusGUID guid; /**< Globally unique ID of server */
|
||||
|
||||
|
|
@ -161,14 +161,14 @@ void _dbus_server_trace_ref (DBusServer *server,
|
|||
|
||||
#define SERVER_LOCK(server) do { \
|
||||
if (TRACE_LOCKS) { _dbus_verbose ("LOCK\n"); } \
|
||||
_dbus_mutex_lock ((server)->mutex); \
|
||||
_dbus_rmutex_lock ((server)->mutex); \
|
||||
TOOK_LOCK_CHECK (server); \
|
||||
} while (0)
|
||||
|
||||
#define SERVER_UNLOCK(server) do { \
|
||||
if (TRACE_LOCKS) { _dbus_verbose ("UNLOCK\n"); } \
|
||||
RELEASING_LOCK_CHECK (server); \
|
||||
_dbus_mutex_unlock ((server)->mutex); \
|
||||
_dbus_rmutex_unlock ((server)->mutex); \
|
||||
} while (0)
|
||||
|
||||
DBUS_END_DECLS
|
||||
|
|
|
|||
|
|
@ -142,7 +142,7 @@ _dbus_server_init_base (DBusServer *server,
|
|||
if (server->address == NULL)
|
||||
goto failed;
|
||||
|
||||
_dbus_mutex_new_at_location (&server->mutex);
|
||||
_dbus_rmutex_new_at_location (&server->mutex);
|
||||
if (server->mutex == NULL)
|
||||
goto failed;
|
||||
|
||||
|
|
@ -161,7 +161,7 @@ _dbus_server_init_base (DBusServer *server,
|
|||
return TRUE;
|
||||
|
||||
failed:
|
||||
_dbus_mutex_free_at_location (&server->mutex);
|
||||
_dbus_rmutex_free_at_location (&server->mutex);
|
||||
server->mutex = NULL;
|
||||
if (server->watches)
|
||||
{
|
||||
|
|
@ -208,7 +208,7 @@ _dbus_server_finalize_base (DBusServer *server)
|
|||
_dbus_watch_list_free (server->watches);
|
||||
_dbus_timeout_list_free (server->timeouts);
|
||||
|
||||
_dbus_mutex_free_at_location (&server->mutex);
|
||||
_dbus_rmutex_free_at_location (&server->mutex);
|
||||
|
||||
dbus_free (server->address);
|
||||
|
||||
|
|
@ -1093,7 +1093,7 @@ dbus_bool_t
|
|||
dbus_server_allocate_data_slot (dbus_int32_t *slot_p)
|
||||
{
|
||||
return _dbus_data_slot_allocator_alloc (&slot_allocator,
|
||||
(DBusMutex **)&_DBUS_LOCK_NAME (server_slots),
|
||||
(DBusRMutex **)&_DBUS_LOCK_NAME (server_slots),
|
||||
slot_p);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -27,19 +27,43 @@
|
|||
#include <dbus/dbus-types.h>
|
||||
#include <dbus/dbus-threads.h>
|
||||
|
||||
/**
|
||||
* @addtogroup DBusThreadsInternals
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* A mutex which is recursive if possible, else non-recursive.
|
||||
* This is typically recursive, but that cannot be relied upon.
|
||||
*/
|
||||
typedef struct DBusRMutex DBusRMutex;
|
||||
|
||||
/**
|
||||
* A mutex suitable for use with condition variables.
|
||||
* This is typically non-recursive.
|
||||
*/
|
||||
typedef struct DBusCMutex DBusCMutex;
|
||||
|
||||
/** @} */
|
||||
|
||||
DBUS_BEGIN_DECLS
|
||||
|
||||
void _dbus_mutex_lock (DBusMutex *mutex);
|
||||
void _dbus_mutex_unlock (DBusMutex *mutex);
|
||||
void _dbus_mutex_new_at_location (DBusMutex **location_p);
|
||||
void _dbus_mutex_free_at_location (DBusMutex **location_p);
|
||||
void _dbus_rmutex_lock (DBusRMutex *mutex);
|
||||
void _dbus_rmutex_unlock (DBusRMutex *mutex);
|
||||
void _dbus_rmutex_new_at_location (DBusRMutex **location_p);
|
||||
void _dbus_rmutex_free_at_location (DBusRMutex **location_p);
|
||||
|
||||
void _dbus_cmutex_lock (DBusCMutex *mutex);
|
||||
void _dbus_cmutex_unlock (DBusCMutex *mutex);
|
||||
void _dbus_cmutex_new_at_location (DBusCMutex **location_p);
|
||||
void _dbus_cmutex_free_at_location (DBusCMutex **location_p);
|
||||
|
||||
DBusCondVar* _dbus_condvar_new (void);
|
||||
void _dbus_condvar_free (DBusCondVar *cond);
|
||||
void _dbus_condvar_wait (DBusCondVar *cond,
|
||||
DBusMutex *mutex);
|
||||
DBusCMutex *mutex);
|
||||
dbus_bool_t _dbus_condvar_wait_timeout (DBusCondVar *cond,
|
||||
DBusMutex *mutex,
|
||||
DBusCMutex *mutex,
|
||||
int timeout_milliseconds);
|
||||
void _dbus_condvar_wake_one (DBusCondVar *cond);
|
||||
void _dbus_condvar_wake_all (DBusCondVar *cond);
|
||||
|
|
|
|||
|
|
@ -38,7 +38,8 @@ static DBusThreadFunctions thread_functions =
|
|||
|
||||
static int thread_init_generation = 0;
|
||||
|
||||
static DBusList *uninitialized_mutex_list = NULL;
|
||||
static DBusList *uninitialized_rmutex_list = NULL;
|
||||
static DBusList *uninitialized_cmutex_list = NULL;
|
||||
static DBusList *uninitialized_condvar_list = NULL;
|
||||
|
||||
/** This is used for the no-op default mutex pointer, just to be distinct from #NULL */
|
||||
|
|
@ -47,12 +48,19 @@ static DBusList *uninitialized_condvar_list = NULL;
|
|||
/** This is used for the no-op default mutex pointer, just to be distinct from #NULL */
|
||||
#define _DBUS_DUMMY_CONDVAR ((DBusCondVar*)0xABCDEF2)
|
||||
|
||||
static void _dbus_mutex_free (DBusMutex *mutex);
|
||||
static void _dbus_mutex_free (DBusMutex *mutex, DBusMutexFreeFunction dtor);
|
||||
static void _dbus_mutex_new_at_location (DBusMutex **location_p,
|
||||
DBusMutexNewFunction ctor,
|
||||
DBusMutexFreeFunction dtor,
|
||||
DBusList **uninitialized);
|
||||
static void _dbus_mutex_free_at_location (DBusMutex **location_p,
|
||||
DBusMutexFreeFunction dtor,
|
||||
DBusList **uninitialized);
|
||||
|
||||
/**
|
||||
* @defgroup DBusThreadsInternals Thread functions
|
||||
* @ingroup DBusInternals
|
||||
* @brief _dbus_mutex_lock(), etc.
|
||||
* @brief _dbus_rmutex_lock(), etc.
|
||||
*
|
||||
* Functions and macros related to threads and thread locks.
|
||||
*
|
||||
|
|
@ -60,9 +68,11 @@ static void _dbus_mutex_free (DBusMutex *mutex);
|
|||
*/
|
||||
|
||||
static DBusMutex *
|
||||
_dbus_mutex_new (void)
|
||||
_dbus_mutex_new (DBusMutexNewFunction ctor)
|
||||
{
|
||||
if (thread_functions.recursive_mutex_new)
|
||||
if (ctor)
|
||||
return ctor ();
|
||||
else if (thread_functions.recursive_mutex_new)
|
||||
return (* thread_functions.recursive_mutex_new) ();
|
||||
else if (thread_functions.mutex_new)
|
||||
return (* thread_functions.mutex_new) ();
|
||||
|
|
@ -76,6 +86,9 @@ _dbus_mutex_new (void)
|
|||
* May return #NULL even if threads are initialized, indicating
|
||||
* out-of-memory.
|
||||
*
|
||||
* If possible, the mutex returned by this function is recursive, to
|
||||
* avoid deadlocks. However, that cannot be relied on.
|
||||
*
|
||||
* The extra level of indirection given by allocating a pointer
|
||||
* to point to the mutex location allows the threading
|
||||
* module to swap out dummy mutexes for real a real mutex so libraries
|
||||
|
|
@ -84,48 +97,127 @@ _dbus_mutex_new (void)
|
|||
* @param location_p the location of the new mutex, can return #NULL on OOM
|
||||
*/
|
||||
void
|
||||
_dbus_mutex_new_at_location (DBusMutex **location_p)
|
||||
_dbus_rmutex_new_at_location (DBusRMutex **location_p)
|
||||
{
|
||||
_dbus_mutex_new_at_location ((DBusMutex **) location_p,
|
||||
thread_functions.recursive_mutex_new,
|
||||
thread_functions.recursive_mutex_free,
|
||||
&uninitialized_rmutex_list);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new mutex using the function supplied to dbus_threads_init(),
|
||||
* or creates a no-op mutex if threads are not initialized.
|
||||
* May return #NULL even if threads are initialized, indicating
|
||||
* out-of-memory.
|
||||
*
|
||||
* The returned mutex is suitable for use with condition variables.
|
||||
*
|
||||
* The extra level of indirection given by allocating a pointer
|
||||
* to point to the mutex location allows the threading
|
||||
* module to swap out dummy mutexes for real a real mutex so libraries
|
||||
* can initialize threads even after the D-Bus API has been used.
|
||||
*
|
||||
* @param location_p the location of the new mutex, can return #NULL on OOM
|
||||
*/
|
||||
void
|
||||
_dbus_cmutex_new_at_location (DBusCMutex **location_p)
|
||||
{
|
||||
_dbus_mutex_new_at_location ((DBusMutex **) location_p,
|
||||
thread_functions.mutex_new,
|
||||
thread_functions.mutex_free,
|
||||
&uninitialized_cmutex_list);
|
||||
}
|
||||
|
||||
static void
|
||||
_dbus_mutex_new_at_location (DBusMutex **location_p,
|
||||
DBusMutexNewFunction ctor,
|
||||
DBusMutexFreeFunction dtor,
|
||||
DBusList **uninitialized)
|
||||
{
|
||||
_dbus_assert (location_p != NULL);
|
||||
|
||||
*location_p = _dbus_mutex_new();
|
||||
*location_p = _dbus_mutex_new (ctor);
|
||||
|
||||
if (thread_init_generation != _dbus_current_generation && *location_p)
|
||||
{
|
||||
if (!_dbus_list_append (&uninitialized_mutex_list, location_p))
|
||||
if (!_dbus_list_append (uninitialized, location_p))
|
||||
{
|
||||
_dbus_mutex_free (*location_p);
|
||||
_dbus_mutex_free (*location_p, dtor);
|
||||
*location_p = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_dbus_mutex_free (DBusMutex *mutex)
|
||||
_dbus_mutex_free (DBusMutex *mutex,
|
||||
DBusMutexFreeFunction dtor)
|
||||
{
|
||||
if (mutex)
|
||||
{
|
||||
if (mutex && thread_functions.recursive_mutex_free)
|
||||
if (dtor)
|
||||
dtor (mutex);
|
||||
else if (mutex && thread_functions.recursive_mutex_free)
|
||||
(* thread_functions.recursive_mutex_free) (mutex);
|
||||
else if (mutex && thread_functions.mutex_free)
|
||||
(* thread_functions.mutex_free) (mutex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Frees a mutex and removes it from the
|
||||
* uninitialized_mutex_list;
|
||||
* does nothing if passed a #NULL pointer.
|
||||
*/
|
||||
void
|
||||
_dbus_mutex_free_at_location (DBusMutex **location_p)
|
||||
static void
|
||||
_dbus_mutex_free_at_location (DBusMutex **location_p,
|
||||
DBusMutexFreeFunction dtor,
|
||||
DBusList **uninitialized)
|
||||
{
|
||||
if (location_p)
|
||||
{
|
||||
if (thread_init_generation != _dbus_current_generation)
|
||||
_dbus_list_remove (&uninitialized_mutex_list, location_p);
|
||||
_dbus_list_remove (uninitialized, location_p);
|
||||
|
||||
_dbus_mutex_free (*location_p);
|
||||
_dbus_mutex_free (*location_p, dtor);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Frees a DBusRMutex and removes it from the
|
||||
* uninitialized mutex list;
|
||||
* does nothing if passed a #NULL pointer.
|
||||
*/
|
||||
void
|
||||
_dbus_rmutex_free_at_location (DBusRMutex **location_p)
|
||||
{
|
||||
_dbus_mutex_free_at_location ((DBusMutex **) location_p,
|
||||
thread_functions.recursive_mutex_free,
|
||||
&uninitialized_rmutex_list);
|
||||
}
|
||||
|
||||
/**
|
||||
* Frees a DBusCMutex and removes it from the
|
||||
* uninitialized mutex list;
|
||||
* does nothing if passed a #NULL pointer.
|
||||
*/
|
||||
void
|
||||
_dbus_cmutex_free_at_location (DBusCMutex **location_p)
|
||||
{
|
||||
_dbus_mutex_free_at_location ((DBusMutex **) location_p,
|
||||
thread_functions.mutex_free,
|
||||
&uninitialized_cmutex_list);
|
||||
}
|
||||
|
||||
/**
|
||||
* Locks a mutex. Does nothing if passed a #NULL pointer.
|
||||
* Locks may be recursive if threading implementation initialized
|
||||
* recursive locks.
|
||||
*/
|
||||
void
|
||||
_dbus_rmutex_lock (DBusRMutex *mutex)
|
||||
{
|
||||
if (mutex)
|
||||
{
|
||||
if (thread_functions.recursive_mutex_lock)
|
||||
(* thread_functions.recursive_mutex_lock) ((DBusMutex *) mutex);
|
||||
else if (thread_functions.mutex_lock)
|
||||
(* thread_functions.mutex_lock) ((DBusMutex *) mutex);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -135,14 +227,14 @@ _dbus_mutex_free_at_location (DBusMutex **location_p)
|
|||
* recursive locks.
|
||||
*/
|
||||
void
|
||||
_dbus_mutex_lock (DBusMutex *mutex)
|
||||
_dbus_cmutex_lock (DBusCMutex *mutex)
|
||||
{
|
||||
if (mutex)
|
||||
if (mutex)
|
||||
{
|
||||
if (thread_functions.recursive_mutex_lock)
|
||||
(* thread_functions.recursive_mutex_lock) (mutex);
|
||||
else if (thread_functions.mutex_lock)
|
||||
(* thread_functions.mutex_lock) (mutex);
|
||||
if (thread_functions.mutex_lock)
|
||||
(* thread_functions.mutex_lock) ((DBusMutex *) mutex);
|
||||
else if (thread_functions.recursive_mutex_lock)
|
||||
(* thread_functions.recursive_mutex_lock) ((DBusMutex *) mutex);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -152,14 +244,31 @@ _dbus_mutex_lock (DBusMutex *mutex)
|
|||
* @returns #TRUE on success
|
||||
*/
|
||||
void
|
||||
_dbus_mutex_unlock (DBusMutex *mutex)
|
||||
_dbus_rmutex_unlock (DBusRMutex *mutex)
|
||||
{
|
||||
if (mutex)
|
||||
{
|
||||
if (thread_functions.recursive_mutex_unlock)
|
||||
(* thread_functions.recursive_mutex_unlock) (mutex);
|
||||
(* thread_functions.recursive_mutex_unlock) ((DBusMutex *) mutex);
|
||||
else if (thread_functions.mutex_unlock)
|
||||
(* thread_functions.mutex_unlock) (mutex);
|
||||
(* thread_functions.mutex_unlock) ((DBusMutex *) mutex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlocks a mutex. Does nothing if passed a #NULL pointer.
|
||||
*
|
||||
* @returns #TRUE on success
|
||||
*/
|
||||
void
|
||||
_dbus_cmutex_unlock (DBusCMutex *mutex)
|
||||
{
|
||||
if (mutex)
|
||||
{
|
||||
if (thread_functions.mutex_unlock)
|
||||
(* thread_functions.mutex_unlock) ((DBusMutex *) mutex);
|
||||
else if (thread_functions.recursive_mutex_unlock)
|
||||
(* thread_functions.recursive_mutex_unlock) ((DBusMutex *) mutex);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -243,10 +352,10 @@ _dbus_condvar_free_at_location (DBusCondVar **location_p)
|
|||
*/
|
||||
void
|
||||
_dbus_condvar_wait (DBusCondVar *cond,
|
||||
DBusMutex *mutex)
|
||||
DBusCMutex *mutex)
|
||||
{
|
||||
if (cond && mutex && thread_functions.condvar_wait)
|
||||
(* thread_functions.condvar_wait) (cond, mutex);
|
||||
(* thread_functions.condvar_wait) (cond, (DBusMutex *) mutex);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -262,11 +371,13 @@ _dbus_condvar_wait (DBusCondVar *cond,
|
|||
*/
|
||||
dbus_bool_t
|
||||
_dbus_condvar_wait_timeout (DBusCondVar *cond,
|
||||
DBusMutex *mutex,
|
||||
DBusCMutex *mutex,
|
||||
int timeout_milliseconds)
|
||||
{
|
||||
if (cond && mutex && thread_functions.condvar_wait)
|
||||
return (* thread_functions.condvar_wait_timeout) (cond, mutex, timeout_milliseconds);
|
||||
return (* thread_functions.condvar_wait_timeout) (cond,
|
||||
(DBusMutex *) mutex,
|
||||
timeout_milliseconds);
|
||||
else
|
||||
return TRUE;
|
||||
}
|
||||
|
|
@ -304,7 +415,7 @@ shutdown_global_locks (void *data)
|
|||
i = 0;
|
||||
while (i < _DBUS_N_GLOBAL_LOCKS)
|
||||
{
|
||||
_dbus_mutex_free (*(locks[i]));
|
||||
_dbus_mutex_free (*(locks[i]), thread_functions.recursive_mutex_free);
|
||||
*(locks[i]) = NULL;
|
||||
++i;
|
||||
}
|
||||
|
|
@ -315,7 +426,8 @@ shutdown_global_locks (void *data)
|
|||
static void
|
||||
shutdown_uninitialized_locks (void *data)
|
||||
{
|
||||
_dbus_list_clear (&uninitialized_mutex_list);
|
||||
_dbus_list_clear (&uninitialized_rmutex_list);
|
||||
_dbus_list_clear (&uninitialized_cmutex_list);
|
||||
_dbus_list_clear (&uninitialized_condvar_list);
|
||||
}
|
||||
|
||||
|
|
@ -326,19 +438,34 @@ init_uninitialized_locks (void)
|
|||
|
||||
_dbus_assert (thread_init_generation != _dbus_current_generation);
|
||||
|
||||
link = uninitialized_mutex_list;
|
||||
link = uninitialized_rmutex_list;
|
||||
while (link != NULL)
|
||||
{
|
||||
DBusMutex **mp;
|
||||
|
||||
mp = (DBusMutex **)link->data;
|
||||
mp = link->data;
|
||||
_dbus_assert (*mp == _DBUS_DUMMY_MUTEX);
|
||||
|
||||
*mp = _dbus_mutex_new ();
|
||||
*mp = _dbus_mutex_new (thread_functions.recursive_mutex_new);
|
||||
if (*mp == NULL)
|
||||
goto fail_mutex;
|
||||
|
||||
link = _dbus_list_get_next_link (&uninitialized_mutex_list, link);
|
||||
link = _dbus_list_get_next_link (&uninitialized_rmutex_list, link);
|
||||
}
|
||||
|
||||
link = uninitialized_cmutex_list;
|
||||
while (link != NULL)
|
||||
{
|
||||
DBusMutex **mp;
|
||||
|
||||
mp = link->data;
|
||||
_dbus_assert (*mp == _DBUS_DUMMY_MUTEX);
|
||||
|
||||
*mp = _dbus_mutex_new (thread_functions.mutex_new);
|
||||
if (*mp == NULL)
|
||||
goto fail_mutex;
|
||||
|
||||
link = _dbus_list_get_next_link (&uninitialized_cmutex_list, link);
|
||||
}
|
||||
|
||||
link = uninitialized_condvar_list;
|
||||
|
|
@ -356,7 +483,8 @@ init_uninitialized_locks (void)
|
|||
link = _dbus_list_get_next_link (&uninitialized_condvar_list, link);
|
||||
}
|
||||
|
||||
_dbus_list_clear (&uninitialized_mutex_list);
|
||||
_dbus_list_clear (&uninitialized_rmutex_list);
|
||||
_dbus_list_clear (&uninitialized_cmutex_list);
|
||||
_dbus_list_clear (&uninitialized_condvar_list);
|
||||
|
||||
if (!_dbus_register_shutdown_func (shutdown_uninitialized_locks,
|
||||
|
|
@ -384,21 +512,38 @@ init_uninitialized_locks (void)
|
|||
}
|
||||
|
||||
fail_mutex:
|
||||
link = uninitialized_mutex_list;
|
||||
link = uninitialized_rmutex_list;
|
||||
while (link != NULL)
|
||||
{
|
||||
DBusMutex **mp;
|
||||
|
||||
mp = (DBusMutex **)link->data;
|
||||
mp = link->data;
|
||||
|
||||
if (*mp != _DBUS_DUMMY_MUTEX)
|
||||
_dbus_mutex_free (*mp);
|
||||
_dbus_mutex_free (*mp, thread_functions.recursive_mutex_free);
|
||||
else
|
||||
break;
|
||||
|
||||
*mp = _DBUS_DUMMY_MUTEX;
|
||||
|
||||
link = _dbus_list_get_next_link (&uninitialized_mutex_list, link);
|
||||
link = _dbus_list_get_next_link (&uninitialized_rmutex_list, link);
|
||||
}
|
||||
|
||||
link = uninitialized_cmutex_list;
|
||||
while (link != NULL)
|
||||
{
|
||||
DBusMutex **mp;
|
||||
|
||||
mp = link->data;
|
||||
|
||||
if (*mp != _DBUS_DUMMY_MUTEX)
|
||||
_dbus_mutex_free (*mp, thread_functions.mutex_free);
|
||||
else
|
||||
break;
|
||||
|
||||
*mp = _DBUS_DUMMY_MUTEX;
|
||||
|
||||
link = _dbus_list_get_next_link (&uninitialized_cmutex_list, link);
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
|
|
@ -408,9 +553,8 @@ static dbus_bool_t
|
|||
init_locks (void)
|
||||
{
|
||||
int i;
|
||||
DBusMutex ***dynamic_global_locks;
|
||||
|
||||
DBusMutex **global_locks[] = {
|
||||
DBusRMutex ***dynamic_global_locks;
|
||||
DBusRMutex **global_locks[] = {
|
||||
#define LOCK_ADDR(name) (& _dbus_lock_##name)
|
||||
LOCK_ADDR (win_fds),
|
||||
LOCK_ADDR (sid_atom_cache),
|
||||
|
|
@ -437,14 +581,14 @@ init_locks (void)
|
|||
|
||||
i = 0;
|
||||
|
||||
dynamic_global_locks = dbus_new (DBusMutex**, _DBUS_N_GLOBAL_LOCKS);
|
||||
dynamic_global_locks = dbus_new (DBusRMutex**, _DBUS_N_GLOBAL_LOCKS);
|
||||
if (dynamic_global_locks == NULL)
|
||||
goto failed;
|
||||
|
||||
while (i < _DBUS_N_ELEMENTS (global_locks))
|
||||
{
|
||||
*global_locks[i] = _dbus_mutex_new ();
|
||||
|
||||
*global_locks[i] = (DBusRMutex *) _dbus_mutex_new (thread_functions.recursive_mutex_new);
|
||||
|
||||
if (*global_locks[i] == NULL)
|
||||
goto failed;
|
||||
|
||||
|
|
@ -467,7 +611,8 @@ init_locks (void)
|
|||
|
||||
for (i = i - 1; i >= 0; i--)
|
||||
{
|
||||
_dbus_mutex_free (*global_locks[i]);
|
||||
_dbus_mutex_free ((DBusMutex *) *global_locks[i],
|
||||
thread_functions.recursive_mutex_free);
|
||||
*global_locks[i] = NULL;
|
||||
}
|
||||
return FALSE;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue