From 89e6dfd29cfbdb92f15e8fb2bde76d94a4c5a7b3 Mon Sep 17 00:00:00 2001 From: Alexander Larsson Date: Wed, 26 Feb 2003 15:52:25 +0000 Subject: 2003-02-26 Alexander Larsson * configure.in: Set DBUS_GLIB_THREADS_LIBS for apps using gthread-2.0 * dbus/dbus-connection.c: * dbus/dbus-connection.h: Fix _dbus_connection_acquire_io_path and _dbus_connection_acquire_dispatch. Add dbus_connection_set_wakeup_main_function and use it when queueing incoming and outgoing messages. * dbus/dbus-dataslot.c: Threadsafe usage of DBusDataSlotAllocator * dbus/dbus-message.c: (dbus_message_get_args_iter): dbus_new can fail. * dbus/dbus-server-unix.c: Add todo comment * glib/dbus-gmain.c: Implement the new wakeup functions for glib. * glib/Makefile.am: * glib/test-thread-client.c: * glib/test-thread-server.c: * glib/test-thread.h: Initial cut at some thread test code. Not really done yet. --- dbus/dbus-connection.c | 87 ++++++++++++++++++++++++++++++++++++++++++++----- dbus/dbus-connection.h | 31 ++++++++++-------- dbus/dbus-dataslot.c | 20 +++++++++++- dbus/dbus-message.c | 13 +++++--- dbus/dbus-server-unix.c | 5 +++ 5 files changed, 128 insertions(+), 28 deletions(-) (limited to 'dbus') diff --git a/dbus/dbus-connection.c b/dbus/dbus-connection.c index 6fb4e84c..4990cff3 100644 --- a/dbus/dbus-connection.c +++ b/dbus/dbus-connection.c @@ -105,6 +105,10 @@ struct DBusConnection int client_serial; /**< Client serial. Increments each time a message is sent */ DBusList *disconnect_message_link; /**< Preallocated list node for queueing the disconnection message */ + + DBusWakeupMainFunction wakeup_main_function; /**< Function to wake up the mainloop */ + void *wakeup_main_data; /**< Application data for wakeup_main_function */ + DBusFreeFunction free_wakeup_main_data; /**< free wakeup_main_data */ }; typedef struct @@ -147,6 +151,19 @@ _dbus_connection_unlock (DBusConnection *connection) dbus_mutex_unlock (connection->mutex); } +/** + * Wakes up the main loop if it is sleeping + * Needed if we're e.g. queueing outgoing messages + * on a thread while the mainloop sleeps. + * + * @param connection the connection. + */ +static void +_dbus_connection_wakeup_mainloop (DBusConnection *connection) +{ + if (connection->wakeup_main_function) + (*connection->wakeup_main_function) (connection->wakeup_main_data); +} /** * Adds a message to the incoming message queue, returning #FALSE @@ -187,6 +204,8 @@ _dbus_connection_queue_received_message (DBusConnection *connection, dbus_message_ref (message); connection->n_incoming += 1; + _dbus_connection_wakeup_mainloop (connection); + _dbus_verbose ("Incoming message %p added to queue, %d incoming\n", message, connection->n_incoming); @@ -211,6 +230,8 @@ _dbus_connection_queue_synthesized_message_link (DBusConnection *connection, connection->n_incoming += 1; + _dbus_connection_wakeup_mainloop (connection); + _dbus_verbose ("Incoming synthesized message %p added to queue, %d incoming\n", link->data, connection->n_incoming); } @@ -388,13 +409,17 @@ _dbus_connection_acquire_io_path (DBusConnection *connection, int timeout_milliseconds) { dbus_bool_t res = TRUE; - if (timeout_milliseconds != -1) - res = dbus_condvar_wait_timeout (connection->io_path_cond, - connection->mutex, - timeout_milliseconds); - else - dbus_condvar_wait (connection->io_path_cond, connection->mutex); + if (connection->io_path_acquired) + { + if (timeout_milliseconds != -1) + res = dbus_condvar_wait_timeout (connection->io_path_cond, + connection->mutex, + timeout_milliseconds); + else + dbus_condvar_wait (connection->io_path_cond, connection->mutex); + } + if (res) { _dbus_assert (!connection->io_path_acquired); @@ -774,6 +799,9 @@ _dbus_connection_last_unref (DBusConnection *connection) DBusHashIter iter; DBusList *link; + /* You have to disconnect the connection before unref:ing it. Otherwise + * you won't get the disconnected message. + */ _dbus_assert (!_dbus_transport_get_is_connected (connection->transport)); if (connection->connection_counter != NULL) @@ -953,7 +981,7 @@ dbus_connection_get_is_authenticated (DBusConnection *connection) dbus_bool_t dbus_connection_send_message (DBusConnection *connection, DBusMessage *message, - dbus_int32_t *client_serial, + dbus_int32_t *client_serial, DBusResultCode *result) { @@ -988,7 +1016,9 @@ dbus_connection_send_message (DBusConnection *connection, if (connection->n_outgoing == 1) _dbus_transport_messages_pending (connection->transport, - connection->n_outgoing); + connection->n_outgoing); + + _dbus_connection_wakeup_mainloop (connection); dbus_mutex_unlock (connection->mutex); @@ -1512,7 +1542,8 @@ dbus_connection_pop_message (DBusConnection *connection) static void _dbus_connection_acquire_dispatch (DBusConnection *connection) { - dbus_condvar_wait (connection->dispatch_cond, connection->mutex); + if (connection->dispatch_acquired) + dbus_condvar_wait (connection->dispatch_cond, connection->mutex); _dbus_assert (!connection->dispatch_acquired); connection->dispatch_acquired = TRUE; @@ -1788,6 +1819,44 @@ dbus_connection_set_timeout_functions (DBusConnection *connection, dbus_connection_unref (connection); } +/** + * Sets the mainloop wakeup function for the connection. Thi function is + * responsible for waking up the main loop (if its sleeping) when some some + * change has happened to the connection that the mainloop needs to reconsiders + * (e.g. a message has been queued for writing). + * When using Qt, this typically results in a call to QEventLoop::wakeUp(). + * When using GLib, it would call g_main_context_wakeup(). + * + * + * @param connection the connection. + * @param wakeup_main_function function to wake up the mainloop + * @param data data to pass wakeup_main_function + * @param free_data_function function to be called to free the data. + */ +void +dbus_connection_set_wakeup_main_function (DBusConnection *connection, + DBusWakeupMainFunction wakeup_main_function, + void *data, + DBusFreeFunction free_data_function) +{ + void *old_data; + DBusFreeFunction old_free_data; + + dbus_mutex_lock (connection->mutex); + old_data = connection->wakeup_main_data; + old_free_data = connection->free_wakeup_main_data; + + connection->wakeup_main_function = wakeup_main_function; + connection->wakeup_main_data = data; + connection->free_wakeup_main_data = free_data_function; + + dbus_mutex_unlock (connection->mutex); + + /* Callback outside the lock */ + if (old_free_data) + (*old_free_data) (old_data); +} + /** * Called to notify the connection when a previously-added watch * is ready for reading or writing, or has an exception such diff --git a/dbus/dbus-connection.h b/dbus/dbus-connection.h index 5a91ce82..fd631c6d 100644 --- a/dbus/dbus-connection.h +++ b/dbus/dbus-connection.h @@ -61,6 +61,7 @@ typedef void (* DBusAddWatchFunction) (DBusWatch *watch, typedef void (* DBusRemoveWatchFunction) (DBusWatch *watch, void *data); +typedef void (* DBusWakeupMainFunction) (void *data); typedef void (* DBusAddTimeoutFunction) (DBusTimeout *timeout, void *data); typedef void (* DBusRemoveTimeoutFunction) (DBusTimeout *timeout, @@ -99,19 +100,23 @@ DBusMessage *dbus_connection_send_message_with_reply_and_block (DBusConnection DBusResultCode *result); -void dbus_connection_set_watch_functions (DBusConnection *connection, - DBusAddWatchFunction add_function, - DBusRemoveWatchFunction remove_function, - void *data, - DBusFreeFunction free_data_function); -void dbus_connection_set_timeout_functions (DBusConnection *connection, - DBusAddTimeoutFunction add_function, - DBusRemoveTimeoutFunction remove_function, - void *data, - DBusFreeFunction free_data_function); -void dbus_connection_handle_watch (DBusConnection *connection, - DBusWatch *watch, - unsigned int condition); +void dbus_connection_set_watch_functions (DBusConnection *connection, + DBusAddWatchFunction add_function, + DBusRemoveWatchFunction remove_function, + void *data, + DBusFreeFunction free_data_function); +void dbus_connection_set_timeout_functions (DBusConnection *connection, + DBusAddTimeoutFunction add_function, + DBusRemoveTimeoutFunction remove_function, + void *data, + DBusFreeFunction free_data_function); +void dbus_connection_set_wakeup_main_function (DBusConnection *connection, + DBusWakeupMainFunction wakeup_main_function, + void *data, + DBusFreeFunction free_data_function); +void dbus_connection_handle_watch (DBusConnection *connection, + DBusWatch *watch, + unsigned int condition); diff --git a/dbus/dbus-dataslot.c b/dbus/dbus-dataslot.c index a5909ffc..53fb9e4c 100644 --- a/dbus/dbus-dataslot.c +++ b/dbus/dbus-dataslot.c @@ -177,9 +177,18 @@ _dbus_data_slot_list_set (DBusDataSlotAllocator *allocator, DBusFreeFunction free_data_func, DBusFreeFunction *old_free_func, void **old_data) -{ +{ +#ifndef DBUS_DISABLE_ASSERT + /* We need to take the allocator lock here, because the allocator could + * be e.g. realloc()ing allocated_slots. We avoid doing this if asserts + * are disabled, since then the asserts are empty. + */ + if (!dbus_mutex_lock (allocator->lock)) + return FALSE; _dbus_assert (slot < allocator->n_allocated_slots); _dbus_assert (allocator->allocated_slots[slot] == slot); + dbus_mutex_unlock (allocator->lock); +#endif if (slot >= list->n_slots) { @@ -227,8 +236,17 @@ _dbus_data_slot_list_get (DBusDataSlotAllocator *allocator, DBusDataSlotList *list, int slot) { +#ifndef DBUS_DISABLE_ASSERT + /* We need to take the allocator lock here, because the allocator could + * be e.g. realloc()ing allocated_slots. We avoid doing this if asserts + * are disabled, since then the asserts are empty. + */ + if (!dbus_mutex_lock (allocator->lock)) + return FALSE; _dbus_assert (slot < allocator->n_allocated_slots); _dbus_assert (allocator->allocated_slots[slot] == slot); + dbus_mutex_unlock (allocator->lock); +#endif if (slot >= list->n_slots) return NULL; diff --git a/dbus/dbus-message.c b/dbus/dbus-message.c index 355d6310..1a112a79 100644 --- a/dbus/dbus-message.c +++ b/dbus/dbus-message.c @@ -1725,12 +1725,15 @@ dbus_message_get_args_iter (DBusMessage *message) iter = dbus_new (DBusMessageIter, 1); - dbus_message_ref (message); + if (iter != NULL) + { + dbus_message_ref (message); + + iter->refcount = 1; + iter->message = message; + iter->pos = 0; + } - iter->refcount = 1; - iter->message = message; - iter->pos = 0; - return iter; } diff --git a/dbus/dbus-server-unix.c b/dbus/dbus-server-unix.c index a6635ddc..0a98c53c 100644 --- a/dbus/dbus-server-unix.c +++ b/dbus/dbus-server-unix.c @@ -65,6 +65,11 @@ unix_finalize (DBusServer *server) dbus_free (server); } +/** + * @todo unreffing the connection at the end may cause + * us to drop the last ref to the connection before + * disconnecting it. That is invalid. + */ static void handle_new_client_fd (DBusServer *server, int client_fd) -- cgit