summaryrefslogtreecommitdiffstats
path: root/dbus/dbus-connection.c
diff options
context:
space:
mode:
Diffstat (limited to 'dbus/dbus-connection.c')
-rw-r--r--dbus/dbus-connection.c287
1 files changed, 177 insertions, 110 deletions
diff --git a/dbus/dbus-connection.c b/dbus/dbus-connection.c
index 6309ea44..9da5fb52 100644
--- a/dbus/dbus-connection.c
+++ b/dbus/dbus-connection.c
@@ -132,7 +132,7 @@ static dbus_bool_t _dbus_modify_sigpipe = TRUE;
*/
struct DBusConnection
{
- dbus_atomic_t refcount; /**< Reference count. */
+ DBusAtomic refcount; /**< Reference count. */
DBusMutex *mutex; /**< Lock on the entire DBusConnection */
@@ -176,6 +176,10 @@ struct DBusConnection
DBusFreeFunction free_dispatch_status_data; /**< free dispatch_status_data */
DBusDispatchStatus last_dispatch_status; /**< The last dispatch status we reported to the application. */
+
+ DBusList *link_cache; /**< A cache of linked list links to prevent contention
+ * for the global linked list mempool lock
+ */
};
typedef struct
@@ -193,11 +197,12 @@ typedef struct
static void reply_handler_data_free (ReplyHandlerData *data);
-static void _dbus_connection_remove_timeout_locked (DBusConnection *connection,
- DBusTimeout *timeout);
-static DBusDispatchStatus _dbus_connection_get_dispatch_status_unlocked (DBusConnection *connection);
-static void _dbus_connection_update_dispatch_status_locked (DBusConnection *connection,
- DBusDispatchStatus new_status);
+static void _dbus_connection_remove_timeout_locked (DBusConnection *connection,
+ DBusTimeout *timeout);
+static DBusDispatchStatus _dbus_connection_get_dispatch_status_unlocked (DBusConnection *connection);
+static void _dbus_connection_update_dispatch_status_and_unlock (DBusConnection *connection,
+ DBusDispatchStatus new_status);
+
/**
@@ -365,6 +370,7 @@ _dbus_connection_get_message_to_send (DBusConnection *connection)
/**
* Notifies the connection that a message has been sent, so the
* message can be removed from the outgoing queue.
+ * Called with the connection lock held.
*
* @param connection the connection.
* @param message the message that was sent.
@@ -373,10 +379,18 @@ void
_dbus_connection_message_sent (DBusConnection *connection,
DBusMessage *message)
{
+ DBusList *link;
+
_dbus_assert (_dbus_transport_get_is_authenticated (connection->transport));
- _dbus_assert (message == _dbus_list_get_last (&connection->outgoing_messages));
- _dbus_list_pop_last (&connection->outgoing_messages);
+ link = _dbus_list_get_last_link (&connection->outgoing_messages);
+ _dbus_assert (link != NULL);
+ _dbus_assert (link->data == message);
+
+ /* Save this link in the link cache */
+ _dbus_list_unlink (&connection->outgoing_messages,
+ link);
+ _dbus_list_prepend_link (&connection->link_cache, link);
connection->n_outgoing -= 1;
@@ -384,7 +398,10 @@ _dbus_connection_message_sent (DBusConnection *connection,
message, dbus_message_get_name (message),
connection, connection->n_outgoing);
- _dbus_message_remove_size_counter (message, connection->outgoing_counter);
+ /* Save this link in the link cache also */
+ _dbus_message_remove_size_counter (message, connection->outgoing_counter,
+ &link);
+ _dbus_list_prepend_link (&connection->link_cache, link);
dbus_message_unref (message);
@@ -724,7 +741,7 @@ _dbus_connection_new_for_transport (DBusTransport *transport)
if (_dbus_modify_sigpipe)
_dbus_disable_sigpipe ();
- connection->refcount = 1;
+ connection->refcount.value = 1;
connection->mutex = mutex;
connection->dispatch_cond = dispatch_cond;
connection->io_path_cond = io_path_cond;
@@ -800,8 +817,12 @@ _dbus_connection_new_for_transport (DBusTransport *transport)
void
_dbus_connection_ref_unlocked (DBusConnection *connection)
{
- _dbus_assert (connection->refcount > 0);
- connection->refcount += 1;
+#ifdef DBUS_HAVE_ATOMIC_INT
+ _dbus_atomic_inc (&connection->refcount);
+#else
+ _dbus_assert (connection->refcount.value > 0);
+ connection->refcount.value += 1;
+#endif
}
static dbus_uint32_t
@@ -892,10 +913,9 @@ _dbus_connection_handle_watch (DBusWatch *watch,
_dbus_connection_release_io_path (connection);
status = _dbus_connection_get_dispatch_status_unlocked (connection);
-
- CONNECTION_UNLOCK (connection);
- _dbus_connection_update_dispatch_status_locked (connection, status);
+ /* this calls out to user code */
+ _dbus_connection_update_dispatch_status_and_unlock (connection, status);
return retval;
}
@@ -972,9 +992,9 @@ dbus_connection_ref (DBusConnection *connection)
_dbus_atomic_inc (&connection->refcount);
#else
CONNECTION_LOCK (connection);
- _dbus_assert (connection->refcount > 0);
+ _dbus_assert (connection->refcount.value > 0);
- connection->refcount += 1;
+ connection->refcount.value += 1;
CONNECTION_UNLOCK (connection);
#endif
}
@@ -987,7 +1007,8 @@ free_outgoing_message (void *element,
DBusConnection *connection = data;
_dbus_message_remove_size_counter (message,
- connection->outgoing_counter);
+ connection->outgoing_counter,
+ NULL);
dbus_message_unref (message);
}
@@ -1003,7 +1024,7 @@ _dbus_connection_last_unref (DBusConnection *connection)
_dbus_verbose ("Finalizing connection %p\n", connection);
- _dbus_assert (connection->refcount == 0);
+ _dbus_assert (connection->refcount.value == 0);
/* You have to disconnect the connection before unref:ing it. Otherwise
* you won't get the disconnected message.
@@ -1071,10 +1092,12 @@ _dbus_connection_last_unref (DBusConnection *connection)
dbus_message_unref (message);
_dbus_list_free_link (connection->disconnect_message_link);
}
+
+ _dbus_list_clear (&connection->link_cache);
dbus_condvar_free (connection->dispatch_cond);
dbus_condvar_free (connection->io_path_cond);
- dbus_condvar_free (connection->message_returned_cond);
+ dbus_condvar_free (connection->message_returned_cond);
dbus_mutex_free (connection->mutex);
@@ -1104,17 +1127,17 @@ dbus_connection_unref (DBusConnection *connection)
*/
#ifdef DBUS_HAVE_ATOMIC_INT
- last_unref = (_dbus_atomic_dec (&connection->refcount) == 0);
+ last_unref = (_dbus_atomic_dec (&connection->refcount) == 1);
#else
CONNECTION_LOCK (connection);
- _dbus_assert (connection->refcount > 0);
+ _dbus_assert (connection->refcount.value > 0);
- connection->refcount -= 1;
- last_unref = (connection->refcount == 0);
+ connection->refcount.value -= 1;
+ last_unref = (connection->refcount.value == 0);
#if 0
- printf ("unref() connection %p count = %d\n", connection, connection->refcount);
+ printf ("unref() connection %p count = %d\n", connection, connection->refcount.value);
#endif
CONNECTION_UNLOCK (connection);
@@ -1203,18 +1226,8 @@ struct DBusPreallocatedSend
DBusList *counter_link;
};
-
-/**
- * Preallocates resources needed to send a message, allowing the message
- * to be sent without the possibility of memory allocation failure.
- * Allows apps to create a future guarantee that they can send
- * a message regardless of memory shortages.
- *
- * @param connection the connection we're preallocating for.
- * @returns the preallocated resources, or #NULL
- */
-DBusPreallocatedSend*
-dbus_connection_preallocate_send (DBusConnection *connection)
+static DBusPreallocatedSend*
+_dbus_connection_preallocate_send_unlocked (DBusConnection *connection)
{
DBusPreallocatedSend *preallocated;
@@ -1224,21 +1237,35 @@ dbus_connection_preallocate_send (DBusConnection *connection)
if (preallocated == NULL)
return NULL;
- CONNECTION_LOCK (connection);
-
- preallocated->queue_link = _dbus_list_alloc_link (NULL);
- if (preallocated->queue_link == NULL)
- goto failed_0;
+ if (connection->link_cache != NULL)
+ {
+ preallocated->queue_link =
+ _dbus_list_pop_first_link (&connection->link_cache);
+ preallocated->queue_link->data = NULL;
+ }
+ else
+ {
+ preallocated->queue_link = _dbus_list_alloc_link (NULL);
+ if (preallocated->queue_link == NULL)
+ goto failed_0;
+ }
- preallocated->counter_link = _dbus_list_alloc_link (connection->outgoing_counter);
- if (preallocated->counter_link == NULL)
- goto failed_1;
+ if (connection->link_cache != NULL)
+ {
+ preallocated->counter_link =
+ _dbus_list_pop_first_link (&connection->link_cache);
+ preallocated->counter_link->data = connection->outgoing_counter;
+ }
+ else
+ {
+ preallocated->counter_link = _dbus_list_alloc_link (connection->outgoing_counter);
+ if (preallocated->counter_link == NULL)
+ goto failed_1;
+ }
_dbus_counter_ref (preallocated->counter_link->data);
preallocated->connection = connection;
-
- CONNECTION_UNLOCK (connection);
return preallocated;
@@ -1246,13 +1273,37 @@ dbus_connection_preallocate_send (DBusConnection *connection)
_dbus_list_free_link (preallocated->queue_link);
failed_0:
dbus_free (preallocated);
-
- CONNECTION_UNLOCK (connection);
return NULL;
}
/**
+ * Preallocates resources needed to send a message, allowing the message
+ * to be sent without the possibility of memory allocation failure.
+ * Allows apps to create a future guarantee that they can send
+ * a message regardless of memory shortages.
+ *
+ * @param connection the connection we're preallocating for.
+ * @returns the preallocated resources, or #NULL
+ */
+DBusPreallocatedSend*
+dbus_connection_preallocate_send (DBusConnection *connection)
+{
+ DBusPreallocatedSend *preallocated;
+
+ _dbus_return_val_if_fail (connection != NULL, NULL);
+
+ CONNECTION_LOCK (connection);
+
+ preallocated =
+ _dbus_connection_preallocate_send_unlocked (connection);
+
+ CONNECTION_UNLOCK (connection);
+
+ return preallocated;
+}
+
+/**
* Frees preallocated message-sending resources from
* dbus_connection_preallocate_send(). Should only
* be called if the preallocated resources are not used
@@ -1266,43 +1317,23 @@ dbus_connection_free_preallocated_send (DBusConnection *connection,
DBusPreallocatedSend *preallocated)
{
_dbus_return_if_fail (connection != NULL);
- _dbus_return_if_fail (preallocated != NULL);
+ _dbus_return_if_fail (preallocated != NULL);
_dbus_return_if_fail (connection == preallocated->connection);
-
+
_dbus_list_free_link (preallocated->queue_link);
_dbus_counter_unref (preallocated->counter_link->data);
_dbus_list_free_link (preallocated->counter_link);
dbus_free (preallocated);
}
-/**
- * Sends a message using preallocated resources. This function cannot fail.
- * It works identically to dbus_connection_send() in other respects.
- * Preallocated resources comes from dbus_connection_preallocate_send().
- * This function "consumes" the preallocated resources, they need not
- * be freed separately.
- *
- * @param connection the connection
- * @param preallocated the preallocated resources
- * @param message the message to send
- * @param client_serial return location for client serial assigned to the message
- */
-void
-dbus_connection_send_preallocated (DBusConnection *connection,
- DBusPreallocatedSend *preallocated,
- DBusMessage *message,
- dbus_uint32_t *client_serial)
+static void
+_dbus_connection_send_preallocated_unlocked (DBusConnection *connection,
+ DBusPreallocatedSend *preallocated,
+ DBusMessage *message,
+ dbus_uint32_t *client_serial)
{
dbus_uint32_t serial;
- _dbus_return_if_fail (connection != NULL);
- _dbus_return_if_fail (preallocated != NULL);
- _dbus_return_if_fail (message != NULL);
- _dbus_return_if_fail (preallocated->connection == connection);
- _dbus_return_if_fail (dbus_message_get_name (message) != NULL);
-
- CONNECTION_LOCK (connection);
-
preallocated->queue_link->data = message;
_dbus_list_prepend_link (&connection->outgoing_messages,
preallocated->queue_link);
@@ -1343,8 +1374,37 @@ dbus_connection_send_preallocated (DBusConnection *connection,
connection->n_outgoing);
_dbus_connection_wakeup_mainloop (connection);
+}
- CONNECTION_UNLOCK (connection);
+/**
+ * Sends a message using preallocated resources. This function cannot fail.
+ * It works identically to dbus_connection_send() in other respects.
+ * Preallocated resources comes from dbus_connection_preallocate_send().
+ * This function "consumes" the preallocated resources, they need not
+ * be freed separately.
+ *
+ * @param connection the connection
+ * @param preallocated the preallocated resources
+ * @param message the message to send
+ * @param client_serial return location for client serial assigned to the message
+ */
+void
+dbus_connection_send_preallocated (DBusConnection *connection,
+ DBusPreallocatedSend *preallocated,
+ DBusMessage *message,
+ dbus_uint32_t *client_serial)
+{
+ _dbus_return_if_fail (connection != NULL);
+ _dbus_return_if_fail (preallocated != NULL);
+ _dbus_return_if_fail (message != NULL);
+ _dbus_return_if_fail (preallocated->connection == connection);
+ _dbus_return_if_fail (dbus_message_get_name (message) != NULL);
+
+ CONNECTION_LOCK (connection);
+ _dbus_connection_send_preallocated_unlocked (connection,
+ preallocated,
+ message, client_serial);
+ CONNECTION_UNLOCK (connection);
}
/**
@@ -1374,15 +1434,22 @@ dbus_connection_send (DBusConnection *connection,
_dbus_return_val_if_fail (connection != NULL, FALSE);
_dbus_return_val_if_fail (message != NULL, FALSE);
+
+ CONNECTION_LOCK (connection);
- preallocated = dbus_connection_preallocate_send (connection);
+ preallocated = _dbus_connection_preallocate_send_unlocked (connection);
if (preallocated == NULL)
{
+ CONNECTION_UNLOCK (connection);
return FALSE;
}
else
{
- dbus_connection_send_preallocated (connection, preallocated, message, client_serial);
+ _dbus_connection_send_preallocated_unlocked (connection,
+ preallocated,
+ message,
+ client_serial);
+ CONNECTION_UNLOCK (connection);
return TRUE;
}
}
@@ -1409,10 +1476,9 @@ reply_handler_timeout (void *data)
reply_handler_data->timeout_added = FALSE;
status = _dbus_connection_get_dispatch_status_unlocked (connection);
-
- CONNECTION_UNLOCK (connection);
- _dbus_connection_update_dispatch_status_locked (connection, status);
+ /* Unlocks, and calls out to user code */
+ _dbus_connection_update_dispatch_status_and_unlock (connection, status);
return TRUE;
}
@@ -1711,13 +1777,12 @@ dbus_connection_send_with_reply_and_block (DBusConnection *connection,
if (reply != NULL)
{
status = _dbus_connection_get_dispatch_status_unlocked (connection);
-
- CONNECTION_UNLOCK (connection);
_dbus_verbose ("dbus_connection_send_with_reply_and_block(): got reply %s\n",
dbus_message_get_name (reply));
- _dbus_connection_update_dispatch_status_locked (connection, status);
+ /* Unlocks, and calls out to user code */
+ _dbus_connection_update_dispatch_status_and_unlock (connection, status);
return reply;
}
@@ -1771,10 +1836,9 @@ dbus_connection_send_with_reply_and_block (DBusConnection *connection,
dbus_set_error (error, DBUS_ERROR_NO_REPLY, "Message did not receive a reply");
else
dbus_set_error (error, DBUS_ERROR_DISCONNECTED, "Disconnected prior to receiving a reply");
-
- CONNECTION_UNLOCK (connection);
- _dbus_connection_update_dispatch_status_locked (connection, status);
+ /* unlocks and calls out to user code */
+ _dbus_connection_update_dispatch_status_and_unlock (connection, status);
return NULL;
}
@@ -1806,10 +1870,9 @@ dbus_connection_flush (DBusConnection *connection)
-1);
status = _dbus_connection_get_dispatch_status_unlocked (connection);
-
- CONNECTION_UNLOCK (connection);
- _dbus_connection_update_dispatch_status_locked (connection, status);
+ /* Unlocks and calls out to user code */
+ _dbus_connection_update_dispatch_status_and_unlock (connection, status);
}
/* Call with mutex held. Will drop it while waiting and re-acquire
@@ -2052,7 +2115,7 @@ _dbus_connection_release_dispatch (DBusConnection *connection)
static void
_dbus_connection_failed_pop (DBusConnection *connection,
- DBusList *message_link)
+ DBusList *message_link)
{
_dbus_list_prepend_link (&connection->incoming_messages,
message_link);
@@ -2082,14 +2145,15 @@ _dbus_connection_get_dispatch_status_unlocked (DBusConnection *connection)
}
static void
-_dbus_connection_update_dispatch_status_locked (DBusConnection *connection,
- DBusDispatchStatus new_status)
+_dbus_connection_update_dispatch_status_and_unlock (DBusConnection *connection,
+ DBusDispatchStatus new_status)
{
dbus_bool_t changed;
DBusDispatchStatusFunction function;
void *data;
-
- CONNECTION_LOCK (connection);
+
+ /* We have the lock */
+
_dbus_connection_ref_unlocked (connection);
changed = new_status != connection->last_dispatch_status;
@@ -2098,7 +2162,8 @@ _dbus_connection_update_dispatch_status_locked (DBusConnection *connection,
function = connection->dispatch_status_function;
data = connection->dispatch_status_data;
-
+
+ /* We drop the lock */
CONNECTION_UNLOCK (connection);
if (changed && function)
@@ -2166,15 +2231,15 @@ dbus_connection_dispatch (DBusConnection *connection)
DBusDispatchStatus status;
_dbus_return_val_if_fail (connection != NULL, DBUS_DISPATCH_COMPLETE);
-
- status = dbus_connection_get_dispatch_status (connection);
+
+ CONNECTION_LOCK (connection);
+ status = _dbus_connection_get_dispatch_status_unlocked (connection);
if (status != DBUS_DISPATCH_DATA_REMAINS)
{
- _dbus_connection_update_dispatch_status_locked (connection, status);
+ /* unlocks and calls out to user code */
+ _dbus_connection_update_dispatch_status_and_unlock (connection, status);
return status;
}
-
- CONNECTION_LOCK (connection);
/* We need to ref the connection since the callback could potentially
* drop the last ref to it
@@ -2195,11 +2260,10 @@ dbus_connection_dispatch (DBusConnection *connection)
/* another thread dispatched our stuff */
_dbus_connection_release_dispatch (connection);
- CONNECTION_UNLOCK (connection);
- status = dbus_connection_get_dispatch_status (connection);
+ status = _dbus_connection_get_dispatch_status_unlocked (connection);
- _dbus_connection_update_dispatch_status_locked (connection, status);
+ _dbus_connection_update_dispatch_status_and_unlock (connection, status);
dbus_connection_unref (connection);
@@ -2217,10 +2281,12 @@ dbus_connection_dispatch (DBusConnection *connection)
if (!_dbus_list_copy (&connection->filter_list, &filter_list_copy))
{
_dbus_connection_release_dispatch (connection);
- CONNECTION_UNLOCK (connection);
+
_dbus_connection_failed_pop (connection, message_link);
- _dbus_connection_update_dispatch_status_locked (connection, DBUS_DISPATCH_NEED_MEMORY);
+ /* unlocks and calls user code */
+ _dbus_connection_update_dispatch_status_and_unlock (connection,
+ DBUS_DISPATCH_NEED_MEMORY);
dbus_connection_unref (connection);
@@ -2320,15 +2386,16 @@ dbus_connection_dispatch (DBusConnection *connection)
out:
_dbus_connection_release_dispatch (connection);
- CONNECTION_UNLOCK (connection);
+
_dbus_list_free_link (message_link);
dbus_message_unref (message); /* don't want the message to count in max message limits
* in computing dispatch status
*/
- status = dbus_connection_get_dispatch_status (connection);
+ status = _dbus_connection_get_dispatch_status_unlocked (connection);
- _dbus_connection_update_dispatch_status_locked (connection, status);
+ /* unlocks and calls user code */
+ _dbus_connection_update_dispatch_status_and_unlock (connection, status);
dbus_connection_unref (connection);