From d4e80132af03363a2f861cfd611847ee8758aed9 Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Mon, 12 May 2003 02:44:45 +0000 Subject: 2003-05-11 Havoc Pennington * dbus/dbus-marshal.c (_dbus_marshal_validate_arg): fix to avoid calling _dbus_marshal_validate_arg() for every byte in a byte array, etc. * dbus/dbus-message-handler.c: use atomic reference counting to reduce number of locks slightly; the global lock in here sucks * dbus/dbus-connection.c (_dbus_connection_update_dispatch_status_and_unlock): variant of update_dispatch_status that can be called with lock held; then use in a couple places to reduce locking/unlocking (dbus_connection_send): hold the lock over the whole function instead of acquiring it twice. * dbus/dbus-timeout.c (_dbus_timeout_new): handle OOM * bus/connection.c (bus_connections_setup_connection): fix access to already-freed memory. * dbus/dbus-connection.c: keep a little cache of linked list nodes, to avoid using the global linked list alloc lock in the normal send-message case. Instead we just use the connection lock that we already have to take. * dbus/dbus-list.c (_dbus_list_find_last): new function * dbus/dbus-sysdeps.c (_dbus_atomic_inc, _dbus_atomic_dec): change to use a struct for the atomic type; fix docs, they return value before increment, not after increment. * dbus/dbus-string.c (_dbus_string_append_4_aligned) (_dbus_string_append_8_aligned): new functions to try to microoptimize this operation. (reallocate_for_length): break this out of set_length(), to improve profile info, and also so we can consider inlining the set_length() part. * dbus/dbus-message.c (dbus_message_new_empty_header): init data strings with some preallocation, cuts down on our calls to realloc a fair bit. Though if we can get the "move entire string to empty string" optimization below to kick in here, it would be better. * dbus/dbus-string.c (_dbus_string_move): just call _dbus_string_move_len (_dbus_string_move_len): add a special case for moving an entire string into an empty string; we can just swap the string data instead of doing any reallocs. (_dbus_string_init_preallocated): new function --- ChangeLog | 51 ++++++++ bus/connection.c | 15 ++- dbus/dbus-connection.c | 287 ++++++++++++++++++++++++++---------------- dbus/dbus-list.c | 33 ++++- dbus/dbus-list.h | 2 + dbus/dbus-marshal.c | 121 +++++++++++++++--- dbus/dbus-message-handler.c | 28 ++--- dbus/dbus-message-internal.h | 3 +- dbus/dbus-message.c | 43 ++++--- dbus/dbus-string.c | 293 ++++++++++++++++++++++++++++++++----------- dbus/dbus-string.h | 6 + dbus/dbus-sysdeps.c | 25 ++-- dbus/dbus-sysdeps.h | 10 +- dbus/dbus-timeout.c | 3 + glib/test-profile.c | 16 ++- 15 files changed, 666 insertions(+), 270 deletions(-) diff --git a/ChangeLog b/ChangeLog index cb74a1e0..292693c6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,54 @@ +2003-05-11 Havoc Pennington + + * dbus/dbus-marshal.c (_dbus_marshal_validate_arg): fix to avoid + calling _dbus_marshal_validate_arg() for every byte in a byte + array, etc. + + * dbus/dbus-message-handler.c: use atomic reference counting to + reduce number of locks slightly; the global lock in here sucks + + * dbus/dbus-connection.c + (_dbus_connection_update_dispatch_status_and_unlock): variant of + update_dispatch_status that can be called with lock held; then use + in a couple places to reduce locking/unlocking + (dbus_connection_send): hold the lock over the whole function + instead of acquiring it twice. + + * dbus/dbus-timeout.c (_dbus_timeout_new): handle OOM + + * bus/connection.c (bus_connections_setup_connection): fix access + to already-freed memory. + + * dbus/dbus-connection.c: keep a little cache of linked list + nodes, to avoid using the global linked list alloc lock in the + normal send-message case. Instead we just use the connection lock + that we already have to take. + + * dbus/dbus-list.c (_dbus_list_find_last): new function + + * dbus/dbus-sysdeps.c (_dbus_atomic_inc, _dbus_atomic_dec): + change to use a struct for the atomic type; fix docs, + they return value before increment, not after increment. + + * dbus/dbus-string.c (_dbus_string_append_4_aligned) + (_dbus_string_append_8_aligned): new functions to try to + microoptimize this operation. + (reallocate_for_length): break this out of set_length(), to + improve profile info, and also so we can consider inlining the + set_length() part. + + * dbus/dbus-message.c (dbus_message_new_empty_header): init data + strings with some preallocation, cuts down on our calls to realloc + a fair bit. Though if we can get the "move entire string to empty + string" optimization below to kick in here, it would be better. + + * dbus/dbus-string.c (_dbus_string_move): just call + _dbus_string_move_len + (_dbus_string_move_len): add a special case for moving + an entire string into an empty string; we can just + swap the string data instead of doing any reallocs. + (_dbus_string_init_preallocated): new function + 2003-05-11 Havoc Pennington Write a "test-profile" that does echo client-server with threads; diff --git a/bus/connection.c b/bus/connection.c index 05532dba..70a0eb15 100644 --- a/bus/connection.c +++ b/bus/connection.c @@ -533,7 +533,7 @@ bus_connections_setup_connection (BusConnections *connections, d->connections = connections; d->connection = connection; - + _dbus_get_current_time (&d->connection_tv_sec, &d->connection_tv_usec); @@ -643,18 +643,21 @@ bus_connections_setup_connection (BusConnections *connections, dbus_connection_set_dispatch_status_function (connection, NULL, NULL, NULL); - - if (!dbus_connection_set_data (connection, - connection_data_slot, - NULL, NULL)) - _dbus_assert_not_reached ("failed to set connection data to null"); if (d->link_in_connection_list != NULL) { _dbus_assert (d->link_in_connection_list->next == NULL); _dbus_assert (d->link_in_connection_list->prev == NULL); _dbus_list_free_link (d->link_in_connection_list); + d->link_in_connection_list = NULL; } + + if (!dbus_connection_set_data (connection, + connection_data_slot, + NULL, NULL)) + _dbus_assert_not_reached ("failed to set connection data to null"); + + /* "d" has now been freed */ } return retval; 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,12 +1273,36 @@ 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 @@ -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); diff --git a/dbus/dbus-list.c b/dbus/dbus-list.c index 235ed275..5d2bcd42 100644 --- a/dbus/dbus-list.c +++ b/dbus/dbus-list.c @@ -454,20 +454,43 @@ _dbus_list_remove_last (DBusList **list, { DBusList *link; + link = _dbus_list_find_last (list, data); + if (link) + { + _dbus_list_remove_link (list, link); + return TRUE; + } + else + return FALSE; +} + +/** + * Finds a value in the list. Returns the last link + * with value equal to the given data pointer. + * This is a linear-time operation. + * Returns #NULL if no value found that matches. + * + * @param list address of the list head. + * @param data the value to find. + * @returns the link if found + */ +DBusList* +_dbus_list_find_last (DBusList **list, + void *data) +{ + DBusList *link; + link = _dbus_list_get_last_link (list); while (link != NULL) { if (link->data == data) - { - _dbus_list_remove_link (list, link); - return TRUE; - } + return link; link = _dbus_list_get_prev_link (list, link); } - return FALSE; + return NULL; } /** diff --git a/dbus/dbus-list.h b/dbus/dbus-list.h index f3b37ef8..7aa6c96c 100644 --- a/dbus/dbus-list.h +++ b/dbus/dbus-list.h @@ -60,6 +60,8 @@ dbus_bool_t _dbus_list_remove_last (DBusList **list, void *data); void _dbus_list_remove_link (DBusList **list, DBusList *link); +DBusList* _dbus_list_find_last (DBusList **list, + void *data); void _dbus_list_clear (DBusList **list); DBusList* _dbus_list_get_first_link (DBusList **list); DBusList* _dbus_list_get_last_link (DBusList **list); diff --git a/dbus/dbus-marshal.c b/dbus/dbus-marshal.c index 82de8ffc..ad15ae21 100644 --- a/dbus/dbus-marshal.c +++ b/dbus/dbus-marshal.c @@ -430,13 +430,11 @@ marshal_4_octets (DBusString *str, { _dbus_assert (sizeof (value) == 4); - if (!_dbus_string_align_length (str, sizeof (dbus_uint32_t))) - return FALSE; - if (byte_order != DBUS_COMPILER_BYTE_ORDER) value = DBUS_UINT32_SWAP_LE_BE (value); - return _dbus_string_append_len (str, (const char *)&value, sizeof (dbus_uint32_t)); + return _dbus_string_append_4_aligned (str, + (const unsigned char *)&value); } static dbus_bool_t @@ -445,14 +443,12 @@ marshal_8_octets (DBusString *str, DBusOctets8 value) { _dbus_assert (sizeof (value) == 8); - - if (!_dbus_string_align_length (str, 8)) - return FALSE; if (byte_order != DBUS_COMPILER_BYTE_ORDER) pack_8_octets (value, byte_order, (unsigned char*) &value); /* pack into self, swapping as we go */ - return _dbus_string_append_len (str, (const char *)&value, 8); + return _dbus_string_append_8_aligned (str, + (const unsigned char *)&value); } /** @@ -1646,6 +1642,99 @@ _dbus_marshal_validate_type (const DBusString *str, return FALSE; } +/* Faster validator for array data that doesn't call + * validate_arg for each value + */ +static dbus_bool_t +validate_array_data (const DBusString *str, + int byte_order, + int depth, + int type, + int array_type_pos, + int pos, + int *new_pos, + int end) +{ + switch (type) + { + case DBUS_TYPE_INVALID: + return FALSE; + break; + + case DBUS_TYPE_NIL: + break; + + case DBUS_TYPE_STRING: + case DBUS_TYPE_NAMED: + case DBUS_TYPE_ARRAY: + case DBUS_TYPE_DICT: + /* This clean recursion to validate_arg is what we + * are doing logically for all types, but we don't + * really want to call validate_arg for every byte + * in a byte array, so the primitive types are + * special-cased. + */ + while (pos < end) + { + if (!_dbus_marshal_validate_arg (str, byte_order, depth, + type, array_type_pos, pos, &pos)) + return FALSE; + } + break; + + case DBUS_TYPE_BYTE: + pos = end; + break; + + case DBUS_TYPE_BOOLEAN: + while (pos < end) + { + unsigned char c; + + c = _dbus_string_get_byte (str, pos); + + if (!(c == 0 || c == 1)) + { + _dbus_verbose ("boolean value must be either 0 or 1, not %d\n", c); + return FALSE; + } + + ++pos; + } + break; + + case DBUS_TYPE_INT32: + case DBUS_TYPE_UINT32: + /* Call validate arg one time to check alignment padding + * at start of array + */ + if (!_dbus_marshal_validate_arg (str, byte_order, depth, + type, array_type_pos, pos, &pos)) + return FALSE; + pos = _DBUS_ALIGN_VALUE (end, 4); + break; + + case DBUS_TYPE_INT64: + case DBUS_TYPE_UINT64: + case DBUS_TYPE_DOUBLE: + /* Call validate arg one time to check alignment padding + * at start of array + */ + if (!_dbus_marshal_validate_arg (str, byte_order, depth, + type, array_type_pos, pos, &pos)) + return FALSE; + pos = _DBUS_ALIGN_VALUE (end, 8); + break; + + default: + _dbus_verbose ("Unknown message arg type %d\n", type); + return FALSE; + } + + *new_pos = pos; + + return TRUE; +} /** * Validates an argument of a specific type, checking that it @@ -1726,7 +1815,7 @@ _dbus_marshal_validate_arg (const DBusString *str, c = _dbus_string_get_byte (str, pos); - if (c != 0 && c != 1) + if (!(c == 0 || c == 1)) { _dbus_verbose ("boolean value must be either 0 or 1, not %d\n", c); return FALSE; @@ -1874,13 +1963,11 @@ _dbus_marshal_validate_arg (const DBusString *str, } end = pos + len; - - while (pos < end) - { - if (!_dbus_marshal_validate_arg (str, byte_order, depth + 1, - array_type, array_type_pos, pos, &pos)) - return FALSE; - } + + if (!validate_array_data (str, byte_order, depth + 1, + array_type, array_type_pos, + pos, &pos, end)) + return FALSE; if (pos < end) { @@ -1888,7 +1975,7 @@ _dbus_marshal_validate_arg (const DBusString *str, * but the check is here just to be paranoid. */ _dbus_verbose ("array length %d specified was longer than actual array contents by %d\n", - len, end - pos); + len, end - pos); return FALSE; } diff --git a/dbus/dbus-message-handler.c b/dbus/dbus-message-handler.c index a978ba05..f38e5100 100644 --- a/dbus/dbus-message-handler.c +++ b/dbus/dbus-message-handler.c @@ -1,7 +1,7 @@ /* -*- mode: C; c-file-style: "gnu" -*- */ /* dbus-message-handler.c Sender/receiver of messages. * - * Copyright (C) 2002 Red Hat Inc. + * Copyright (C) 2002, 2003 Red Hat Inc. * * Licensed under the Academic Free License version 1.2 * @@ -47,7 +47,7 @@ _DBUS_DEFINE_GLOBAL_LOCK (message_handler); */ struct DBusMessageHandler { - int refcount; /**< reference count */ + DBusAtomic refcount; /**< reference count */ DBusHandleMessageFunction function; /**< handler function */ void *user_data; /**< user data for function */ @@ -176,7 +176,7 @@ dbus_message_handler_new (DBusHandleMessageFunction function, if (handler == NULL) return NULL; - handler->refcount = 1; + handler->refcount.value = 1; handler->function = function; handler->user_data = user_data; handler->free_user_data = free_user_data; @@ -194,12 +194,8 @@ void dbus_message_handler_ref (DBusMessageHandler *handler) { _dbus_return_if_fail (handler != NULL); - - _DBUS_LOCK (message_handler); - _dbus_assert (handler != NULL); - - handler->refcount += 1; - _DBUS_UNLOCK (message_handler); + + _dbus_atomic_inc (&handler->refcount); } /** @@ -211,21 +207,13 @@ dbus_message_handler_ref (DBusMessageHandler *handler) void dbus_message_handler_unref (DBusMessageHandler *handler) { - int refcount; + dbus_bool_t last_unref; _dbus_return_if_fail (handler != NULL); - - _DBUS_LOCK (message_handler); - - _dbus_assert (handler != NULL); - _dbus_assert (handler->refcount > 0); - handler->refcount -= 1; - refcount = handler->refcount; - - _DBUS_UNLOCK (message_handler); + last_unref = (_dbus_atomic_dec (&handler->refcount) == 1); - if (refcount == 0) + if (last_unref) { DBusList *link; diff --git a/dbus/dbus-message-internal.h b/dbus/dbus-message-internal.h index eb4123c3..53711f3d 100644 --- a/dbus/dbus-message-internal.h +++ b/dbus/dbus-message-internal.h @@ -44,7 +44,8 @@ dbus_bool_t _dbus_message_add_size_counter (DBusMessage *message, void _dbus_message_add_size_counter_link (DBusMessage *message, DBusList *link); void _dbus_message_remove_size_counter (DBusMessage *message, - DBusCounter *counter); + DBusCounter *counter, + DBusList **link_return); DBusMessageLoader* _dbus_message_loader_new (void); void _dbus_message_loader_ref (DBusMessageLoader *loader); diff --git a/dbus/dbus-message.c b/dbus/dbus-message.c index 29209106..7c89d734 100644 --- a/dbus/dbus-message.c +++ b/dbus/dbus-message.c @@ -81,7 +81,7 @@ typedef struct */ struct DBusMessage { - volatile dbus_atomic_t refcount; /**< Reference count */ + DBusAtomic refcount; /**< Reference count */ DBusString header; /**< Header network data, stored * separately from body so we can @@ -772,15 +772,26 @@ _dbus_message_add_size_counter (DBusMessage *message, * the counter by the size of this message. * * @param message the message + * @param link_return return the link used * @param counter the counter */ void _dbus_message_remove_size_counter (DBusMessage *message, - DBusCounter *counter) + DBusCounter *counter, + DBusList **link_return) { - if (!_dbus_list_remove_last (&message->size_counters, - counter)) - _dbus_assert_not_reached ("Removed a message size counter that was not added"); + DBusList *link; + + link = _dbus_list_find_last (&message->size_counters, + counter); + _dbus_assert (link != NULL); + + _dbus_list_unlink (&message->size_counters, + link); + if (link_return) + *link_return = link; + else + _dbus_list_free_link (link); _dbus_counter_adjust (counter, message->size_counter_delta); @@ -898,7 +909,7 @@ dbus_message_new_empty_header (void) if (message == NULL) return NULL; - message->refcount = 1; + message->refcount.value = 1; message->byte_order = DBUS_COMPILER_BYTE_ORDER; message->client_serial = 0; message->reply_serial = 0; @@ -910,13 +921,13 @@ dbus_message_new_empty_header (void) ++i; } - if (!_dbus_string_init (&message->header)) + if (!_dbus_string_init_preallocated (&message->header, 64)) { dbus_free (message); return NULL; } - if (!_dbus_string_init (&message->body)) + if (!_dbus_string_init_preallocated (&message->body, 64)) { _dbus_string_free (&message->header); dbus_free (message); @@ -1076,7 +1087,7 @@ dbus_message_copy (const DBusMessage *message) if (retval == NULL) return NULL; - retval->refcount = 1; + retval->refcount.value = 1; retval->byte_order = message->byte_order; retval->client_serial = message->client_serial; retval->reply_serial = message->reply_serial; @@ -1134,12 +1145,12 @@ dbus_message_copy (const DBusMessage *message) void dbus_message_ref (DBusMessage *message) { - volatile dbus_atomic_t refcount; + dbus_int32_t old_refcount; _dbus_return_if_fail (message != NULL); - refcount = _dbus_atomic_inc (&message->refcount); - _dbus_assert (refcount > 1); + old_refcount = _dbus_atomic_inc (&message->refcount); + _dbus_assert (old_refcount >= 1); } static void @@ -1163,15 +1174,15 @@ free_size_counter (void *element, void dbus_message_unref (DBusMessage *message) { - volatile dbus_atomic_t refcount; + dbus_int32_t old_refcount; _dbus_return_if_fail (message != NULL); - refcount = _dbus_atomic_dec (&message->refcount); + old_refcount = _dbus_atomic_dec (&message->refcount); - _dbus_assert (refcount >= 0); + _dbus_assert (old_refcount >= 0); - if (refcount == 0) + if (old_refcount == 1) { _dbus_list_foreach (&message->size_counters, free_size_counter, message); diff --git a/dbus/dbus-string.c b/dbus/dbus-string.c index 65d2fb1b..c6f929a8 100644 --- a/dbus/dbus-string.c +++ b/dbus/dbus-string.c @@ -169,14 +169,17 @@ undo_alignment (DBusRealString *real) } /** - * Initializes a string. The string starts life with zero length. The - * string must eventually be freed with _dbus_string_free(). + * Initializes a string that can be up to the given allocation size + * before it has to realloc. The string starts life with zero length. + * The string must eventually be freed with _dbus_string_free(). * * @param str memory to hold the string + * @param allocate_size amount to preallocate * @returns #TRUE on success, #FALSE if no memory */ dbus_bool_t -_dbus_string_init (DBusString *str) +_dbus_string_init_preallocated (DBusString *str, + int allocate_size) { DBusRealString *real; @@ -192,11 +195,11 @@ _dbus_string_init (DBusString *str) * an existing string, e.g. in _dbus_string_steal_data() */ - real->str = dbus_malloc (ALLOCATION_PADDING); + real->str = dbus_malloc (ALLOCATION_PADDING + allocate_size); if (real->str == NULL) return FALSE; - real->allocated = ALLOCATION_PADDING; + real->allocated = ALLOCATION_PADDING + allocate_size; real->len = 0; real->str[real->len] = '\0'; @@ -211,6 +214,19 @@ _dbus_string_init (DBusString *str) return TRUE; } +/** + * Initializes a string. The string starts life with zero length. The + * string must eventually be freed with _dbus_string_free(). + * + * @param str memory to hold the string + * @returns #TRUE on success, #FALSE if no memory + */ +dbus_bool_t +_dbus_string_init (DBusString *str) +{ + return _dbus_string_init_preallocated (str, 0); +} + /* The max length thing is sort of a historical artifact * from a feature that turned out to be dumb; perhaps * we should purge it entirely. The problem with @@ -345,55 +361,64 @@ _dbus_string_lock (DBusString *str) #endif /* DBUS_BUILD_TESTS */ static dbus_bool_t -set_length (DBusRealString *real, - int new_length) +reallocate_for_length (DBusRealString *real, + int new_length) { - /* Note, we are setting the length without nul termination */ - - /* exceeding max length is the same as failure to allocate memory */ - if (new_length > real->max_length) - return FALSE; - - if (new_length > (real->allocated - ALLOCATION_PADDING)) - { - int new_allocated; - char *new_str; + int new_allocated; + char *new_str; - /* at least double our old allocation to avoid O(n), avoiding - * overflow - */ - if (real->allocated > (MAX_MAX_LENGTH + ALLOCATION_PADDING) / 2) - new_allocated = MAX_MAX_LENGTH + ALLOCATION_PADDING; - else - new_allocated = real->allocated * 2; + /* at least double our old allocation to avoid O(n), avoiding + * overflow + */ + if (real->allocated > (MAX_MAX_LENGTH + ALLOCATION_PADDING) / 2) + new_allocated = MAX_MAX_LENGTH + ALLOCATION_PADDING; + else + new_allocated = real->allocated * 2; - /* if you change the code just above here, run the tests without - * the following before you commit - */ + /* if you change the code just above here, run the tests without + * the following before you commit + */ #ifdef DBUS_BUILD_TESTS - new_allocated = 0; /* ensure a realloc every time so that we go - * through all malloc failure codepaths - */ + new_allocated = 0; /* ensure a realloc every time so that we go + * through all malloc failure codepaths + */ #endif - /* But be sure we always alloc at least space for the new length */ - new_allocated = MAX (new_allocated, new_length + ALLOCATION_PADDING); - - new_str = dbus_realloc (real->str - real->align_offset, new_allocated); - if (new_str == NULL) - return FALSE; + /* But be sure we always alloc at least space for the new length */ + new_allocated = MAX (new_allocated, new_length + ALLOCATION_PADDING); - real->str = new_str + real->align_offset; - real->allocated = new_allocated; - fixup_alignment (real); - } + _dbus_assert (new_allocated >= real->allocated); /* code relies on this */ + new_str = dbus_realloc (real->str - real->align_offset, new_allocated); + if (new_str == NULL) + return FALSE; - real->len = new_length; - real->str[real->len] = '\0'; + real->str = new_str + real->align_offset; + real->allocated = new_allocated; + fixup_alignment (real); return TRUE; } +static dbus_bool_t +set_length (DBusRealString *real, + int new_length) +{ + /* Note, we are setting the length not including nul termination */ + + /* exceeding max length is the same as failure to allocate memory */ + if (new_length > real->max_length) + return FALSE; + else if (new_length > (real->allocated - ALLOCATION_PADDING) && + !reallocate_for_length (real, new_length)) + return FALSE; + else + { + real->len = new_length; + real->str[real->len] = '\0'; + return TRUE; + } +} + static dbus_bool_t open_gap (int len, DBusRealString *dest, @@ -795,17 +820,10 @@ _dbus_string_set_length (DBusString *str, return set_length (real, length); } -/** - * Align the length of a string to a specific alignment (typically 4 or 8) - * by appending nul bytes to the string. - * - * @param str a string - * @param alignment the alignment - * @returns #FALSE if no memory - */ -dbus_bool_t -_dbus_string_align_length (DBusString *str, - int alignment) +static dbus_bool_t +align_length_then_lengthen (DBusString *str, + int alignment, + int then_lengthen_by) { unsigned long new_len; /* ulong to avoid _DBUS_ALIGN_VALUE overflow */ int delta; @@ -814,8 +832,9 @@ _dbus_string_align_length (DBusString *str, _dbus_assert (alignment <= 8); /* it has to be a bug if > 8 */ new_len = _DBUS_ALIGN_VALUE (real->len, alignment); - if (new_len > (unsigned long) real->max_length) + if (new_len > (unsigned long) real->max_length - then_lengthen_by) return FALSE; + new_len += then_lengthen_by; delta = new_len - real->len; _dbus_assert (delta >= 0); @@ -826,12 +845,38 @@ _dbus_string_align_length (DBusString *str, if (!set_length (real, new_len)) return FALSE; - memset (real->str + (new_len - delta), - '\0', delta); - + /* delta == padding + then_lengthen_by + * new_len == old_len + padding + then_lengthen_by + */ + if (then_lengthen_by < delta) + { + unsigned int i; + i = new_len - delta; + while (i < (new_len - then_lengthen_by)) + { + real->str[i] = '\0'; + ++i; + } + } + return TRUE; } +/** + * Align the length of a string to a specific alignment (typically 4 or 8) + * by appending nul bytes to the string. + * + * @param str a string + * @param alignment the alignment + * @returns #FALSE if no memory + */ +dbus_bool_t +_dbus_string_align_length (DBusString *str, + int alignment) +{ + return align_length_then_lengthen (str, alignment, 0); +} + static dbus_bool_t append (DBusRealString *real, const char *buffer, @@ -873,6 +918,74 @@ _dbus_string_append (DBusString *str, return append (real, buffer, buffer_len); } +/** + * Appends 4 bytes aligned on a 4 byte boundary + * with any alignment padding initialized to 0. + * + * @param str the DBusString + * @param octets 4 bytes to append + * @returns #FALSE if not enough memory. + */ +dbus_bool_t +_dbus_string_append_4_aligned (DBusString *str, + const unsigned char octets[4]) +{ + dbus_uint32_t *p; + DBUS_STRING_PREAMBLE (str); + + if (!align_length_then_lengthen (str, 4, 4)) + return FALSE; + + p = (dbus_uint32_t*) (real->str + (real->len - 4)); + *p = *((dbus_uint32_t*)octets); + + return TRUE; +} + +/** + * Appends 8 bytes aligned on an 8 byte boundary + * with any alignment padding initialized to 0. + * + * @param str the DBusString + * @param octets 4 bytes to append + * @returns #FALSE if not enough memory. + */ +dbus_bool_t +_dbus_string_append_8_aligned (DBusString *str, + const unsigned char octets[8]) +{ +#ifdef DBUS_HAVE_INT64 + dbus_uint64_t *p; + DBUS_STRING_PREAMBLE (str); + + if (!align_length_then_lengthen (str, 8, 8)) + return FALSE; + + p = (dbus_uint64_t*) (real->str + (real->len - 8)); + *p = *((dbus_uint64_t*)octets); +#else + char *p; + DBUS_STRING_PREAMBLE (str); + + if (!align_length_then_lengthen (str, 8, 8)) + return FALSE; + + p = real->str + (real->len - 8); + + *p++ = octets[0]; + *p++ = octets[1]; + *p++ = octets[2]; + *p++ = octets[3]; + *p++ = octets[4]; + *p++ = octets[5]; + *p++ = octets[6]; + *p++ = octets[7]; + _dbus_assert (p == (real->str + real->len)); +#endif + + return TRUE; +} + /** * Appends block of bytes with the given length to a DBusString. * @@ -1080,18 +1193,12 @@ _dbus_string_move (DBusString *source, DBusString *dest, int insert_at) { - DBUS_STRING_COPY_PREAMBLE (source, start, dest, insert_at); + DBusRealString *real_source = (DBusRealString*) source; + _dbus_assert (start <= real_source->len); - if (!copy (real_source, start, - real_source->len - start, - real_dest, - insert_at)) - return FALSE; - - delete (real_source, start, - real_source->len - start); - - return TRUE; + return _dbus_string_move_len (source, start, + real_source->len - start, + dest, insert_at); } /** @@ -1121,6 +1228,9 @@ _dbus_string_copy (const DBusString *source, /** * Like _dbus_string_move(), but can move a segment from * the middle of the source string. + * + * @todo this doesn't do anything with max_length field. + * we should probably just kill the max_length field though. * * @param source the source string * @param start first byte of source string to move @@ -1141,15 +1251,48 @@ _dbus_string_move_len (DBusString *source, _dbus_assert (len >= 0); _dbus_assert ((start + len) <= real_source->len); - if (!copy (real_source, start, len, - real_dest, - insert_at)) - return FALSE; - delete (real_source, start, - len); + if (len == 0) + { + return TRUE; + } + else if (start == 0 && + len == real_source->len && + real_dest->len == 0) + { + /* Short-circuit moving an entire existing string to an empty string + * by just swapping the buffers. + */ + /* we assume ->constant doesn't matter as you can't have + * a constant string involved in a move. + */ +#define ASSIGN_DATA(a, b) do { \ + (a)->str = (b)->str; \ + (a)->len = (b)->len; \ + (a)->allocated = (b)->allocated; \ + (a)->align_offset = (b)->align_offset; \ + } while (0) + + DBusRealString tmp; - return TRUE; + ASSIGN_DATA (&tmp, real_source); + ASSIGN_DATA (real_source, real_dest); + ASSIGN_DATA (real_dest, &tmp); + + return TRUE; + } + else + { + if (!copy (real_source, start, len, + real_dest, + insert_at)) + return FALSE; + + delete (real_source, start, + len); + + return TRUE; + } } /** diff --git a/dbus/dbus-string.h b/dbus/dbus-string.h index b9b298ae..8fa13805 100644 --- a/dbus/dbus-string.h +++ b/dbus/dbus-string.h @@ -51,6 +51,8 @@ void _dbus_string_init_const (DBusString *str, void _dbus_string_init_const_len (DBusString *str, const char *value, int len); +dbus_bool_t _dbus_string_init_preallocated (DBusString *str, + int allocate_size); void _dbus_string_free (DBusString *str); void _dbus_string_lock (DBusString *str); char* _dbus_string_get_data (DBusString *str); @@ -105,6 +107,10 @@ dbus_bool_t _dbus_string_append_byte (DBusString *str, unsigned char byte); dbus_bool_t _dbus_string_append_unichar (DBusString *str, dbus_unichar_t ch); +dbus_bool_t _dbus_string_append_4_aligned (DBusString *str, + const unsigned char octets[4]); +dbus_bool_t _dbus_string_append_8_aligned (DBusString *str, + const unsigned char octets[8]); void _dbus_string_delete (DBusString *str, int start, int len); diff --git a/dbus/dbus-sysdeps.c b/dbus/dbus-sysdeps.c index c813a83c..e2975c30 100644 --- a/dbus/dbus-sysdeps.c +++ b/dbus/dbus-sysdeps.c @@ -1792,19 +1792,18 @@ _dbus_getgid (void) _DBUS_DEFINE_GLOBAL_LOCK (atomic); - #ifdef DBUS_USE_ATOMIC_INT_486 /* Taken from CVS version 1.7 of glibc's sysdeps/i386/i486/atomicity.h */ /* Since the asm stuff here is gcc-specific we go ahead and use "inline" also */ -static inline dbus_atomic_t -atomic_exchange_and_add (volatile dbus_atomic_t *atomic, - volatile dbus_atomic_t val) +static inline dbus_int32_t +atomic_exchange_and_add (DBusAtomic *atomic, + volatile dbus_int32_t val) { - register dbus_atomic_t result; + register dbus_int32_t result; __asm__ __volatile__ ("lock; xaddl %0,%1" - : "=r" (result), "=m" (*atomic) - : "0" (val), "m" (*atomic)); + : "=r" (result), "=m" (atomic->value) + : "0" (val), "m" (atomic->value)); return result; } #endif @@ -1813,12 +1812,12 @@ atomic_exchange_and_add (volatile dbus_atomic_t *atomic, * Atomically increments an integer * * @param atomic pointer to the integer to increment - * @returns the value after incrementing + * @returns the value before incrementing * * @todo implement arch-specific faster atomic ops */ -dbus_atomic_t -_dbus_atomic_inc (volatile dbus_atomic_t *atomic) +dbus_int32_t +_dbus_atomic_inc (DBusAtomic *atomic) { #ifdef DBUS_USE_ATOMIC_INT_486 return atomic_exchange_and_add (atomic, 1); @@ -1837,12 +1836,12 @@ _dbus_atomic_inc (volatile dbus_atomic_t *atomic) * Atomically decrement an integer * * @param atomic pointer to the integer to decrement - * @returns the value after decrementing + * @returns the value before decrementing * * @todo implement arch-specific faster atomic ops */ -dbus_atomic_t -_dbus_atomic_dec (volatile dbus_atomic_t *atomic) +dbus_int32_t +_dbus_atomic_dec (DBusAtomic *atomic) { #ifdef DBUS_USE_ATOMIC_INT_486 return atomic_exchange_and_add (atomic, -1); diff --git a/dbus/dbus-sysdeps.h b/dbus/dbus-sysdeps.h index 2ae455b1..7a4696f3 100644 --- a/dbus/dbus-sysdeps.h +++ b/dbus/dbus-sysdeps.h @@ -169,10 +169,14 @@ unsigned long _dbus_getpid (void); dbus_uid_t _dbus_getuid (void); dbus_gid_t _dbus_getgid (void); -typedef dbus_int32_t dbus_atomic_t; +typedef struct DBusAtomic DBusAtomic; +struct DBusAtomic +{ + volatile dbus_int32_t value; +}; -dbus_atomic_t _dbus_atomic_inc (volatile dbus_atomic_t *atomic); -dbus_atomic_t _dbus_atomic_dec (volatile dbus_atomic_t *atomic); +dbus_int32_t _dbus_atomic_inc (DBusAtomic *atomic); +dbus_int32_t _dbus_atomic_dec (DBusAtomic *atomic); #define _DBUS_POLLIN 0x0001 /* There is data to read */ #define _DBUS_POLLPRI 0x0002 /* There is urgent data to read */ diff --git a/dbus/dbus-timeout.c b/dbus/dbus-timeout.c index 625fbb74..289d6347 100644 --- a/dbus/dbus-timeout.c +++ b/dbus/dbus-timeout.c @@ -64,6 +64,9 @@ _dbus_timeout_new (int interval, DBusTimeout *timeout; timeout = dbus_new0 (DBusTimeout, 1); + if (timeout == NULL) + return NULL; + timeout->refcount = 1; timeout->interval = interval; diff --git a/glib/test-profile.c b/glib/test-profile.c index 6173f3a5..d53f7626 100644 --- a/glib/test-profile.c +++ b/glib/test-profile.c @@ -27,9 +27,11 @@ #include #define N_CLIENT_THREADS 1 -#define N_ITERATIONS 2000 +#define N_ITERATIONS 100 +#define PAYLOAD_SIZE 1000 #define ECHO_MESSAGE "org.freedesktop.DBus.Test.EchoProfile" static const char *address; +static unsigned char *payload; static void send_echo_message (DBusConnection *connection) @@ -40,7 +42,12 @@ send_echo_message (DBusConnection *connection) dbus_message_append_args (message, DBUS_TYPE_STRING, "Hello World!", DBUS_TYPE_INT32, 123456, +#if 1 + DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, + payload, PAYLOAD_SIZE, +#endif DBUS_TYPE_INVALID); + dbus_connection_send (connection, message, NULL); dbus_message_unref (message); dbus_connection_flush (connection); @@ -63,12 +70,12 @@ client_filter (DBusMessageHandler *handler, ECHO_MESSAGE)) { *iterations += 1; - send_echo_message (connection); - if (*iterations > N_ITERATIONS) + if (*iterations >= N_ITERATIONS) { g_print ("Completed %d iterations\n", N_ITERATIONS); exit (0); } + send_echo_message (connection); } return DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS; @@ -95,7 +102,7 @@ thread_func (void *data) exit (1); } - iterations = 0; + iterations = 1; handler = dbus_message_handler_new (client_filter, &iterations, NULL); @@ -188,6 +195,7 @@ main (int argc, char *argv[]) } address = dbus_server_get_address (server); + payload = g_malloc (PAYLOAD_SIZE); dbus_server_set_new_connection_function (server, new_connection_callback, -- cgit