From ab10ae902d8aa7c2b98fd080a7458127b1b8e648 Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Sun, 11 May 2003 07:59:08 +0000 Subject: 2003-05-11 Havoc Pennington Write a "test-profile" that does echo client-server with threads; profile reveals lock contention, memcpy/realloc of buffers, and UTF-8 validation as hot spots. 20% of lock contention eliminated with dbus_atomic_inc/dec implementation on x86. Much remaining contention is global mempool locks for GList and DBusList. * dbus/dbus-sysdeps.c (_dbus_atomic_inc, _dbus_atomic_dec): add x86 implementation * dbus/dbus-connection.c (struct DBusConnection): use dbus_atomic_t for the reference count * dbus/dbus-message.c (struct DBusMessage): declare dbus_atomic_t values as volatile * configure.in: code to detect ability to use atomic integer operations in assembly, from GLib patch * dbus/dbus-internals.c (_dbus_verbose_real): call getpid every time, tired of it being wrong in threads and forked processes * glib/test-profile.c: a little program to bounce messages back and forth between threads and eat CPU * dbus/dbus-connection.c: add debug spew macros for debugging thread locks; include config.h at top; fix deadlock in dbus_connection_flush() --- ChangeLog | 30 ++++++ bus/connection.c | 6 +- configure.in | 23 +++++ dbus/dbus-auth.c | 3 - dbus/dbus-connection.c | 241 ++++++++++++++++++++++++++++--------------------- dbus/dbus-internals.c | 4 +- dbus/dbus-message.c | 6 +- dbus/dbus-spawn.c | 1 + dbus/dbus-sysdeps.c | 30 +++++- dbus/dbus-sysdeps.h | 6 +- dbus/dbus-threads.c | 2 +- glib/Makefile.am | 33 ++++--- glib/test-profile.c | 215 +++++++++++++++++++++++++++++++++++++++++++ 13 files changed, 468 insertions(+), 132 deletions(-) create mode 100644 glib/test-profile.c diff --git a/ChangeLog b/ChangeLog index 43321cc0..cb74a1e0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,33 @@ +2003-05-11 Havoc Pennington + + Write a "test-profile" that does echo client-server with threads; + profile reveals lock contention, memcpy/realloc of buffers, and + UTF-8 validation as hot spots. 20% of lock contention eliminated + with dbus_atomic_inc/dec implementation on x86. Much remaining + contention is global mempool locks for GList and DBusList. + + * dbus/dbus-sysdeps.c (_dbus_atomic_inc, _dbus_atomic_dec): add + x86 implementation + + * dbus/dbus-connection.c (struct DBusConnection): use + dbus_atomic_t for the reference count + + * dbus/dbus-message.c (struct DBusMessage): declare + dbus_atomic_t values as volatile + + * configure.in: code to detect ability to use atomic integer + operations in assembly, from GLib patch + + * dbus/dbus-internals.c (_dbus_verbose_real): call getpid every + time, tired of it being wrong in threads and forked processes + + * glib/test-profile.c: a little program to bounce messages back + and forth between threads and eat CPU + + * dbus/dbus-connection.c: add debug spew macros for debugging + thread locks; include config.h at top; fix deadlock in + dbus_connection_flush() + 2003-05-08 Havoc Pennington * dbus/dbus-spawn.c: s/_exit/exit/ because it was keeping gcov diff --git a/bus/connection.c b/bus/connection.c index 6bb53148..05532dba 100644 --- a/bus/connection.c +++ b/bus/connection.c @@ -292,9 +292,9 @@ connection_watch_callback (DBusWatch *watch, void *data) { /* FIXME this can be done in dbus-mainloop.c - * if the code in activation.c for the babysitter - * watch handler is fixed. - */ + * if the code in activation.c for the babysitter + * watch handler is fixed. + */ #if 0 _dbus_verbose ("Calling handle_watch\n"); diff --git a/configure.in b/configure.in index 18cb519e..f95da565 100644 --- a/configure.in +++ b/configure.in @@ -205,6 +205,28 @@ AC_SUBST(DBUS_HAVE_INT64) ## byte order AC_C_BIGENDIAN +#### Atomic integers (checks by Sebastian Wilhelmi for GLib) +AC_MSG_CHECKING([whether to use inline assembler routines for atomic integers]) +have_atomic_inc=no +if test x"$GCC" = xyes; then + case $host_cpu in + i386) + AC_MSG_RESULT([no]) + ;; + i?86) + AC_MSG_RESULT([i486]) + AC_DEFINE_UNQUOTED(DBUS_USE_ATOMIC_INT_486, 1, [Use atomic integer implementation for 486]) + have_atomic_inc=yes + ;; + *) + AC_MSG_RESULT([no]) + ;; + esac +fi +if test x$have_atomic_inc = xyes ; then + AC_DEFINE_UNQUOTED(DBUS_HAVE_ATOMIC_INT, 1, [Some atomic integer implementation present]) +fi + #### Various functions AC_CHECK_LIB(socket,socket) AC_CHECK_LIB(nsl,gethostbyname) @@ -598,6 +620,7 @@ else TEST_SOCKET_DIR=$DEFAULT_SOCKET_DIR fi AC_SUBST(TEST_SOCKET_DIR) +AC_DEFINE_UNQUOTED(DBUS_TEST_SOCKET_DIR, "$TEST_SOCKET_DIR", [Where to put test sockets]) if ! test -z "$with_session_socket_dir" ; then DBUS_SESSION_SOCKET_DIR="$with_session_socket_dir" diff --git a/dbus/dbus-auth.c b/dbus/dbus-auth.c index 4da39667..b496dba0 100644 --- a/dbus/dbus-auth.c +++ b/dbus/dbus-auth.c @@ -39,9 +39,6 @@ * is first established, and also manage any encryption used over a * connection. * - * The file doc/dbus-sasl-profile.txt documents the network protocol - * used for authentication. - * * @todo some SASL profiles require sending the empty string as a * challenge/response, but we don't currently allow that in our * protocol. diff --git a/dbus/dbus-connection.c b/dbus/dbus-connection.c index 688841d7..6309ea44 100644 --- a/dbus/dbus-connection.c +++ b/dbus/dbus-connection.c @@ -21,6 +21,7 @@ * */ +#include #include "dbus-connection.h" #include "dbus-list.h" #include "dbus-timeout.h" @@ -35,6 +36,20 @@ #include "dbus-protocol.h" #include "dbus-dataslot.h" +#if 1 +#define CONNECTION_LOCK(connection) do { \ + _dbus_verbose (" LOCK: %s\n", _DBUS_FUNCTION_NAME); \ + dbus_mutex_lock ((connection)->mutex); \ + } while (0) +#define CONNECTION_UNLOCK(connection) do { \ + _dbus_verbose (" UNLOCK: %s\n", _DBUS_FUNCTION_NAME); \ + dbus_mutex_unlock ((connection)->mutex); \ + } while (0) +#else +#define CONNECTION_LOCK(connection) dbus_mutex_lock ((connection)->mutex) +#define CONNECTION_UNLOCK(connection) dbus_mutex_unlock ((connection)->mutex) +#endif + /** * @defgroup DBusConnection DBusConnection * @ingroup DBus @@ -117,7 +132,7 @@ static dbus_bool_t _dbus_modify_sigpipe = TRUE; */ struct DBusConnection { - int refcount; /**< Reference count. */ + dbus_atomic_t refcount; /**< Reference count. */ DBusMutex *mutex; /**< Lock on the entire DBusConnection */ @@ -193,7 +208,7 @@ static void _dbus_connection_update_dispatch_status_locked (DBusCo void _dbus_connection_lock (DBusConnection *connection) { - dbus_mutex_lock (connection->mutex); + CONNECTION_LOCK (connection); } /** @@ -204,7 +219,7 @@ _dbus_connection_lock (DBusConnection *connection) void _dbus_connection_unlock (DBusConnection *connection) { - dbus_mutex_unlock (connection->mutex); + CONNECTION_UNLOCK (connection); } /** @@ -478,9 +493,9 @@ static void _dbus_connection_remove_timeout_locked (DBusConnection *connection, DBusTimeout *timeout) { - dbus_mutex_lock (connection->mutex); + CONNECTION_LOCK (connection); _dbus_connection_remove_timeout (connection, timeout); - dbus_mutex_unlock (connection->mutex); + CONNECTION_UNLOCK (connection); } /** @@ -820,7 +835,7 @@ _dbus_connection_handler_destroyed_locked (DBusConnection *connection, DBusHashIter iter; DBusList *link; - dbus_mutex_lock (connection->mutex); + CONNECTION_LOCK (connection); _dbus_hash_iter_init (connection->handler_table, &iter); while (_dbus_hash_iter_next (&iter)) @@ -843,7 +858,7 @@ _dbus_connection_handler_destroyed_locked (DBusConnection *connection, link = next; } - dbus_mutex_unlock (connection->mutex); + CONNECTION_UNLOCK (connection); } /** @@ -870,7 +885,7 @@ _dbus_connection_handle_watch (DBusWatch *watch, connection = data; - dbus_mutex_lock (connection->mutex); + CONNECTION_LOCK (connection); _dbus_connection_acquire_io_path (connection, -1); retval = _dbus_transport_handle_watch (connection->transport, watch, condition); @@ -878,7 +893,7 @@ _dbus_connection_handle_watch (DBusWatch *watch, status = _dbus_connection_get_dispatch_status_unlocked (connection); - dbus_mutex_unlock (connection->mutex); + CONNECTION_UNLOCK (connection); _dbus_connection_update_dispatch_status_locked (connection, status); @@ -948,12 +963,20 @@ void dbus_connection_ref (DBusConnection *connection) { _dbus_return_if_fail (connection != NULL); + + /* The connection lock is better than the global + * lock in the atomic increment fallback + */ - dbus_mutex_lock (connection->mutex); +#ifdef DBUS_HAVE_ATOMIC_INT + _dbus_atomic_inc (&connection->refcount); +#else + CONNECTION_LOCK (connection); _dbus_assert (connection->refcount > 0); connection->refcount += 1; - dbus_mutex_unlock (connection->mutex); + CONNECTION_UNLOCK (connection); +#endif } static void @@ -1075,8 +1098,15 @@ dbus_connection_unref (DBusConnection *connection) dbus_bool_t last_unref; _dbus_return_if_fail (connection != NULL); + + /* The connection lock is better than the global + * lock in the atomic increment fallback + */ - dbus_mutex_lock (connection->mutex); +#ifdef DBUS_HAVE_ATOMIC_INT + last_unref = (_dbus_atomic_dec (&connection->refcount) == 0); +#else + CONNECTION_LOCK (connection); _dbus_assert (connection->refcount > 0); @@ -1087,8 +1117,9 @@ dbus_connection_unref (DBusConnection *connection) printf ("unref() connection %p count = %d\n", connection, connection->refcount); #endif - dbus_mutex_unlock (connection->mutex); - + CONNECTION_UNLOCK (connection); +#endif + if (last_unref) _dbus_connection_last_unref (connection); } @@ -1108,9 +1139,15 @@ dbus_connection_disconnect (DBusConnection *connection) { _dbus_return_if_fail (connection != NULL); - dbus_mutex_lock (connection->mutex); + CONNECTION_LOCK (connection); _dbus_transport_disconnect (connection->transport); - dbus_mutex_unlock (connection->mutex); + CONNECTION_UNLOCK (connection); +} + +static dbus_bool_t +_dbus_connection_get_is_connected_unlocked (DBusConnection *connection) +{ + return _dbus_transport_get_is_connected (connection->transport); } /** @@ -1130,9 +1167,9 @@ dbus_connection_get_is_connected (DBusConnection *connection) _dbus_return_val_if_fail (connection != NULL, FALSE); - dbus_mutex_lock (connection->mutex); - res = _dbus_transport_get_is_connected (connection->transport); - dbus_mutex_unlock (connection->mutex); + CONNECTION_LOCK (connection); + res = _dbus_connection_get_is_connected_unlocked (connection); + CONNECTION_UNLOCK (connection); return res; } @@ -1152,9 +1189,9 @@ dbus_connection_get_is_authenticated (DBusConnection *connection) _dbus_return_val_if_fail (connection != NULL, FALSE); - dbus_mutex_lock (connection->mutex); + CONNECTION_LOCK (connection); res = _dbus_transport_get_is_authenticated (connection->transport); - dbus_mutex_unlock (connection->mutex); + CONNECTION_UNLOCK (connection); return res; } @@ -1187,7 +1224,7 @@ dbus_connection_preallocate_send (DBusConnection *connection) if (preallocated == NULL) return NULL; - dbus_mutex_lock (connection->mutex); + CONNECTION_LOCK (connection); preallocated->queue_link = _dbus_list_alloc_link (NULL); if (preallocated->queue_link == NULL) @@ -1201,7 +1238,7 @@ dbus_connection_preallocate_send (DBusConnection *connection) preallocated->connection = connection; - dbus_mutex_unlock (connection->mutex); + CONNECTION_UNLOCK (connection); return preallocated; @@ -1210,7 +1247,7 @@ dbus_connection_preallocate_send (DBusConnection *connection) failed_0: dbus_free (preallocated); - dbus_mutex_unlock (connection->mutex); + CONNECTION_UNLOCK (connection); return NULL; } @@ -1264,7 +1301,7 @@ dbus_connection_send_preallocated (DBusConnection *connection, _dbus_return_if_fail (preallocated->connection == connection); _dbus_return_if_fail (dbus_message_get_name (message) != NULL); - dbus_mutex_lock (connection->mutex); + CONNECTION_LOCK (connection); preallocated->queue_link->data = message; _dbus_list_prepend_link (&connection->outgoing_messages, @@ -1307,7 +1344,7 @@ dbus_connection_send_preallocated (DBusConnection *connection, _dbus_connection_wakeup_mainloop (connection); - dbus_mutex_unlock (connection->mutex); + CONNECTION_UNLOCK (connection); } /** @@ -1359,7 +1396,7 @@ reply_handler_timeout (void *data) connection = reply_handler_data->connection; - dbus_mutex_lock (connection->mutex); + CONNECTION_LOCK (connection); if (reply_handler_data->timeout_link) { _dbus_connection_queue_synthesized_message_link (connection, @@ -1373,7 +1410,7 @@ reply_handler_timeout (void *data) status = _dbus_connection_get_dispatch_status_unlocked (connection); - dbus_mutex_unlock (connection->mutex); + CONNECTION_UNLOCK (connection); _dbus_connection_update_dispatch_status_locked (connection, status); @@ -1474,14 +1511,14 @@ dbus_connection_send_with_reply (DBusConnection *connection, return FALSE; } - dbus_mutex_lock (connection->mutex); + CONNECTION_LOCK (connection); /* Add timeout */ if (!_dbus_connection_add_timeout (connection, timeout)) { reply_handler_data_free (data); _dbus_timeout_unref (timeout); - dbus_mutex_unlock (connection->mutex); + CONNECTION_UNLOCK (connection); return FALSE; } @@ -1494,7 +1531,7 @@ dbus_connection_send_with_reply (DBusConnection *connection, if (!_dbus_message_handler_add_connection (reply_handler, connection)) { - dbus_mutex_unlock (connection->mutex); + CONNECTION_UNLOCK (connection); reply_handler_data_free (data); return FALSE; } @@ -1516,7 +1553,7 @@ dbus_connection_send_with_reply (DBusConnection *connection, "No reply within specified time"); if (!reply) { - dbus_mutex_unlock (connection->mutex); + CONNECTION_UNLOCK (connection); reply_handler_data_free (data); return FALSE; } @@ -1524,7 +1561,7 @@ dbus_connection_send_with_reply (DBusConnection *connection, reply_link = _dbus_list_alloc_link (reply); if (!reply) { - dbus_mutex_unlock (connection->mutex); + CONNECTION_UNLOCK (connection); dbus_message_unref (reply); reply_handler_data_free (data); return FALSE; @@ -1535,12 +1572,12 @@ dbus_connection_send_with_reply (DBusConnection *connection, /* Insert the serial in the pending replies hash. */ if (!_dbus_hash_table_insert_int (connection->pending_replies, serial, data)) { - dbus_mutex_unlock (connection->mutex); + CONNECTION_UNLOCK (connection); reply_handler_data_free (data); return FALSE; } - dbus_mutex_unlock (connection->mutex); + CONNECTION_UNLOCK (connection); if (!dbus_connection_send (connection, message, NULL)) { @@ -1637,7 +1674,7 @@ dbus_connection_send_with_reply_and_block (DBusConnection *connection, /* Flush message queue */ dbus_connection_flush (connection); - dbus_mutex_lock (connection->mutex); + CONNECTION_LOCK (connection); _dbus_get_current_time (&start_tv_sec, &start_tv_usec); end_tv_sec = start_tv_sec + timeout_milliseconds / 1000; @@ -1675,7 +1712,7 @@ dbus_connection_send_with_reply_and_block (DBusConnection *connection, { status = _dbus_connection_get_dispatch_status_unlocked (connection); - dbus_mutex_unlock (connection->mutex); + CONNECTION_UNLOCK (connection); _dbus_verbose ("dbus_connection_send_with_reply_and_block(): got reply %s\n", dbus_message_get_name (reply)); @@ -1735,7 +1772,7 @@ dbus_connection_send_with_reply_and_block (DBusConnection *connection, else dbus_set_error (error, DBUS_ERROR_DISCONNECTED, "Disconnected prior to receiving a reply"); - dbus_mutex_unlock (connection->mutex); + CONNECTION_UNLOCK (connection); _dbus_connection_update_dispatch_status_locked (connection, status); @@ -1759,9 +1796,9 @@ dbus_connection_flush (DBusConnection *connection) _dbus_return_if_fail (connection != NULL); - dbus_mutex_lock (connection->mutex); + CONNECTION_LOCK (connection); while (connection->n_outgoing > 0 && - dbus_connection_get_is_connected (connection)) + _dbus_connection_get_is_connected_unlocked (connection)) _dbus_connection_do_iteration (connection, DBUS_ITERATION_DO_READING | DBUS_ITERATION_DO_WRITING | @@ -1770,7 +1807,7 @@ dbus_connection_flush (DBusConnection *connection) status = _dbus_connection_get_dispatch_status_unlocked (connection); - dbus_mutex_unlock (connection->mutex); + CONNECTION_UNLOCK (connection); _dbus_connection_update_dispatch_status_locked (connection, status); } @@ -1816,7 +1853,7 @@ dbus_connection_borrow_message (DBusConnection *connection) if (status != DBUS_DISPATCH_DATA_REMAINS) return NULL; - dbus_mutex_lock (connection->mutex); + CONNECTION_LOCK (connection); if (connection->message_borrowed != NULL) _dbus_connection_wait_for_borrowed (connection); @@ -1826,7 +1863,7 @@ dbus_connection_borrow_message (DBusConnection *connection) if (message) connection->message_borrowed = message; - dbus_mutex_unlock (connection->mutex); + CONNECTION_UNLOCK (connection); return message; } @@ -1844,14 +1881,14 @@ dbus_connection_return_message (DBusConnection *connection, _dbus_return_if_fail (connection != NULL); _dbus_return_if_fail (message != NULL); - dbus_mutex_lock (connection->mutex); + CONNECTION_LOCK (connection); _dbus_assert (message == connection->message_borrowed); connection->message_borrowed = NULL; dbus_condvar_wake_all (connection->message_returned_cond); - dbus_mutex_unlock (connection->mutex); + CONNECTION_UNLOCK (connection); } /** @@ -1872,7 +1909,7 @@ dbus_connection_steal_borrowed_message (DBusConnection *connection, _dbus_return_if_fail (connection != NULL); _dbus_return_if_fail (message != NULL); - dbus_mutex_lock (connection->mutex); + CONNECTION_LOCK (connection); _dbus_assert (message == connection->message_borrowed); @@ -1887,7 +1924,7 @@ dbus_connection_steal_borrowed_message (DBusConnection *connection, connection->message_borrowed = NULL; dbus_condvar_wake_all (connection->message_returned_cond); - dbus_mutex_unlock (connection->mutex); + CONNECTION_UNLOCK (connection); } /* See dbus_connection_pop_message, but requires the caller to own @@ -1968,13 +2005,13 @@ dbus_connection_pop_message (DBusConnection *connection) if (status != DBUS_DISPATCH_DATA_REMAINS) return NULL; - dbus_mutex_lock (connection->mutex); + CONNECTION_LOCK (connection); message = _dbus_connection_pop_message_unlocked (connection); _dbus_verbose ("Returning popped message %p\n", message); - dbus_mutex_unlock (connection->mutex); + CONNECTION_UNLOCK (connection); return message; } @@ -2052,7 +2089,7 @@ _dbus_connection_update_dispatch_status_locked (DBusConnection *connection, DBusDispatchStatusFunction function; void *data; - dbus_mutex_lock (connection->mutex); + CONNECTION_LOCK (connection); _dbus_connection_ref_unlocked (connection); changed = new_status != connection->last_dispatch_status; @@ -2062,7 +2099,7 @@ _dbus_connection_update_dispatch_status_locked (DBusConnection *connection, function = connection->dispatch_status_function; data = connection->dispatch_status_data; - dbus_mutex_unlock (connection->mutex); + CONNECTION_UNLOCK (connection); if (changed && function) { @@ -2093,11 +2130,11 @@ dbus_connection_get_dispatch_status (DBusConnection *connection) _dbus_return_val_if_fail (connection != NULL, DBUS_DISPATCH_COMPLETE); - dbus_mutex_lock (connection->mutex); + CONNECTION_LOCK (connection); status = _dbus_connection_get_dispatch_status_unlocked (connection); - dbus_mutex_unlock (connection->mutex); + CONNECTION_UNLOCK (connection); return status; } @@ -2137,7 +2174,7 @@ dbus_connection_dispatch (DBusConnection *connection) return status; } - dbus_mutex_lock (connection->mutex); + CONNECTION_LOCK (connection); /* We need to ref the connection since the callback could potentially * drop the last ref to it @@ -2158,7 +2195,7 @@ dbus_connection_dispatch (DBusConnection *connection) /* another thread dispatched our stuff */ _dbus_connection_release_dispatch (connection); - dbus_mutex_unlock (connection->mutex); + CONNECTION_UNLOCK (connection); status = dbus_connection_get_dispatch_status (connection); @@ -2180,7 +2217,7 @@ dbus_connection_dispatch (DBusConnection *connection) if (!_dbus_list_copy (&connection->filter_list, &filter_list_copy)) { _dbus_connection_release_dispatch (connection); - dbus_mutex_unlock (connection->mutex); + CONNECTION_UNLOCK (connection); _dbus_connection_failed_pop (connection, message_link); _dbus_connection_update_dispatch_status_locked (connection, DBUS_DISPATCH_NEED_MEMORY); @@ -2197,7 +2234,7 @@ dbus_connection_dispatch (DBusConnection *connection) /* We're still protected from dispatch() reentrancy here * since we acquired the dispatcher */ - dbus_mutex_unlock (connection->mutex); + CONNECTION_UNLOCK (connection); link = _dbus_list_get_first_link (&filter_list_copy); while (link != NULL) @@ -2220,7 +2257,7 @@ dbus_connection_dispatch (DBusConnection *connection) NULL); _dbus_list_clear (&filter_list_copy); - dbus_mutex_lock (connection->mutex); + CONNECTION_LOCK (connection); /* Did a reply we were waiting on get filtered? */ if (reply_handler_data && result == DBUS_HANDLER_RESULT_REMOVE_MESSAGE) @@ -2244,14 +2281,14 @@ dbus_connection_dispatch (DBusConnection *connection) if (reply_handler_data) { - dbus_mutex_unlock (connection->mutex); + CONNECTION_UNLOCK (connection); _dbus_verbose (" running reply handler on message %p\n", message); result = _dbus_message_handler_handle_message (reply_handler_data->handler, connection, message); reply_handler_data_free (reply_handler_data); - dbus_mutex_lock (connection->mutex); + CONNECTION_LOCK (connection); goto out; } @@ -2265,14 +2302,14 @@ dbus_connection_dispatch (DBusConnection *connection) /* We're still protected from dispatch() reentrancy here * since we acquired the dispatcher */ - dbus_mutex_unlock (connection->mutex); + CONNECTION_UNLOCK (connection); _dbus_verbose (" running app handler on message %p (%s)\n", message, dbus_message_get_name (message)); result = _dbus_message_handler_handle_message (handler, connection, message); - dbus_mutex_lock (connection->mutex); + CONNECTION_LOCK (connection); if (result == DBUS_HANDLER_RESULT_REMOVE_MESSAGE) goto out; } @@ -2283,7 +2320,7 @@ dbus_connection_dispatch (DBusConnection *connection) out: _dbus_connection_release_dispatch (connection); - dbus_mutex_unlock (connection->mutex); + 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 @@ -2368,7 +2405,7 @@ dbus_connection_set_watch_functions (DBusConnection *connection, _dbus_return_val_if_fail (connection != NULL, FALSE); - dbus_mutex_lock (connection->mutex); + CONNECTION_LOCK (connection); /* ref connection for slightly better reentrancy */ _dbus_connection_ref_unlocked (connection); @@ -2380,7 +2417,7 @@ dbus_connection_set_watch_functions (DBusConnection *connection, toggled_function, data, free_data_function); - dbus_mutex_unlock (connection->mutex); + CONNECTION_UNLOCK (connection); /* drop our paranoid refcount */ dbus_connection_unref (connection); @@ -2432,7 +2469,7 @@ dbus_connection_set_timeout_functions (DBusConnection *connection, _dbus_return_val_if_fail (connection != NULL, FALSE); - dbus_mutex_lock (connection->mutex); + CONNECTION_LOCK (connection); /* ref connection for slightly better reentrancy */ _dbus_connection_ref_unlocked (connection); @@ -2441,7 +2478,7 @@ dbus_connection_set_timeout_functions (DBusConnection *connection, toggled_function, data, free_data_function); - dbus_mutex_unlock (connection->mutex); + CONNECTION_UNLOCK (connection); /* drop our paranoid refcount */ dbus_connection_unref (connection); @@ -2473,7 +2510,7 @@ dbus_connection_set_wakeup_main_function (DBusConnection *connection, _dbus_return_if_fail (connection != NULL); - dbus_mutex_lock (connection->mutex); + CONNECTION_LOCK (connection); old_data = connection->wakeup_main_data; old_free_data = connection->free_wakeup_main_data; @@ -2481,7 +2518,7 @@ dbus_connection_set_wakeup_main_function (DBusConnection *connection, connection->wakeup_main_data = data; connection->free_wakeup_main_data = free_data_function; - dbus_mutex_unlock (connection->mutex); + CONNECTION_UNLOCK (connection); /* Callback outside the lock */ if (old_free_data) @@ -2515,7 +2552,7 @@ dbus_connection_set_dispatch_status_function (DBusConnection *connec _dbus_return_if_fail (connection != NULL); - dbus_mutex_lock (connection->mutex); + CONNECTION_LOCK (connection); old_data = connection->dispatch_status_data; old_free_data = connection->free_dispatch_status_data; @@ -2523,7 +2560,7 @@ dbus_connection_set_dispatch_status_function (DBusConnection *connec connection->dispatch_status_data = data; connection->free_dispatch_status_data = free_data_function; - dbus_mutex_unlock (connection->mutex); + CONNECTION_UNLOCK (connection); /* Callback outside the lock */ if (old_free_data) @@ -2550,14 +2587,14 @@ dbus_connection_get_unix_user (DBusConnection *connection, _dbus_return_val_if_fail (connection != NULL, FALSE); _dbus_return_val_if_fail (uid != NULL, FALSE); - dbus_mutex_lock (connection->mutex); + CONNECTION_LOCK (connection); if (!_dbus_transport_get_is_authenticated (connection->transport)) result = FALSE; else result = _dbus_transport_get_unix_user (connection->transport, uid); - dbus_mutex_unlock (connection->mutex); + CONNECTION_UNLOCK (connection); return result; } @@ -2589,11 +2626,11 @@ dbus_connection_set_unix_user_function (DBusConnection *connection, _dbus_return_if_fail (connection != NULL); - dbus_mutex_lock (connection->mutex); + CONNECTION_LOCK (connection); _dbus_transport_set_unix_user_function (connection->transport, function, data, free_data_function, &old_data, &old_free_function); - dbus_mutex_unlock (connection->mutex); + CONNECTION_UNLOCK (connection); if (old_free_function != NULL) (* old_free_function) (old_data); @@ -2624,11 +2661,11 @@ dbus_connection_add_filter (DBusConnection *connection, { _dbus_return_val_if_fail (connection != NULL, FALSE); _dbus_return_val_if_fail (handler != NULL, FALSE); - - dbus_mutex_lock (connection->mutex); + + CONNECTION_LOCK (connection); if (!_dbus_message_handler_add_connection (handler, connection)) { - dbus_mutex_unlock (connection->mutex); + CONNECTION_UNLOCK (connection); return FALSE; } @@ -2636,11 +2673,11 @@ dbus_connection_add_filter (DBusConnection *connection, handler)) { _dbus_message_handler_remove_connection (handler, connection); - dbus_mutex_unlock (connection->mutex); + CONNECTION_UNLOCK (connection); return FALSE; } - dbus_mutex_unlock (connection->mutex); + CONNECTION_UNLOCK (connection); return TRUE; } @@ -2662,17 +2699,17 @@ dbus_connection_remove_filter (DBusConnection *connection, _dbus_return_if_fail (connection != NULL); _dbus_return_if_fail (handler != NULL); - dbus_mutex_lock (connection->mutex); + CONNECTION_LOCK (connection); if (!_dbus_list_remove_last (&connection->filter_list, handler)) { _dbus_warn ("Tried to remove a DBusConnection filter that had not been added\n"); - dbus_mutex_unlock (connection->mutex); + CONNECTION_UNLOCK (connection); return; } _dbus_message_handler_remove_connection (handler, connection); - dbus_mutex_unlock (connection->mutex); + CONNECTION_UNLOCK (connection); } /** @@ -2714,7 +2751,7 @@ dbus_connection_register_handler (DBusConnection *connection, _dbus_return_val_if_fail (n_messages >= 0, FALSE); _dbus_return_val_if_fail (n_messages == 0 || messages_to_handle != NULL, FALSE); - dbus_mutex_lock (connection->mutex); + CONNECTION_LOCK (connection); i = 0; while (i < n_messages) { @@ -2753,7 +2790,7 @@ dbus_connection_register_handler (DBusConnection *connection, ++i; } - dbus_mutex_unlock (connection->mutex); + CONNECTION_UNLOCK (connection); return TRUE; failed: @@ -2765,7 +2802,7 @@ dbus_connection_register_handler (DBusConnection *connection, messages_to_handle, i); - dbus_mutex_unlock (connection->mutex); + CONNECTION_UNLOCK (connection); return FALSE; } @@ -2792,7 +2829,7 @@ dbus_connection_unregister_handler (DBusConnection *connection, _dbus_return_if_fail (n_messages >= 0); _dbus_return_if_fail (n_messages == 0 || messages_to_handle != NULL); - dbus_mutex_lock (connection->mutex); + CONNECTION_LOCK (connection); i = 0; while (i < n_messages) { @@ -2819,7 +2856,7 @@ dbus_connection_unregister_handler (DBusConnection *connection, ++i; } - dbus_mutex_unlock (connection->mutex); + CONNECTION_UNLOCK (connection); } static DBusDataSlotAllocator slot_allocator; @@ -2885,14 +2922,14 @@ dbus_connection_set_data (DBusConnection *connection, _dbus_return_val_if_fail (connection != NULL, FALSE); _dbus_return_val_if_fail (slot >= 0, FALSE); - dbus_mutex_lock (connection->mutex); + CONNECTION_LOCK (connection); retval = _dbus_data_slot_list_set (&slot_allocator, &connection->slot_list, slot, data, free_data_func, &old_free_func, &old_data); - dbus_mutex_unlock (connection->mutex); + CONNECTION_UNLOCK (connection); if (retval) { @@ -2920,13 +2957,13 @@ dbus_connection_get_data (DBusConnection *connection, _dbus_return_val_if_fail (connection != NULL, NULL); - dbus_mutex_lock (connection->mutex); + CONNECTION_LOCK (connection); res = _dbus_data_slot_list_get (&slot_allocator, &connection->slot_list, slot); - dbus_mutex_unlock (connection->mutex); + CONNECTION_UNLOCK (connection); return res; } @@ -2957,10 +2994,10 @@ dbus_connection_set_max_message_size (DBusConnection *connection, { _dbus_return_if_fail (connection != NULL); - dbus_mutex_lock (connection->mutex); + CONNECTION_LOCK (connection); _dbus_transport_set_max_message_size (connection->transport, size); - dbus_mutex_unlock (connection->mutex); + CONNECTION_UNLOCK (connection); } /** @@ -2976,9 +3013,9 @@ dbus_connection_get_max_message_size (DBusConnection *connection) _dbus_return_val_if_fail (connection != NULL, 0); - dbus_mutex_lock (connection->mutex); + CONNECTION_LOCK (connection); res = _dbus_transport_get_max_message_size (connection->transport); - dbus_mutex_unlock (connection->mutex); + CONNECTION_UNLOCK (connection); return res; } @@ -3013,10 +3050,10 @@ dbus_connection_set_max_received_size (DBusConnection *connection, { _dbus_return_if_fail (connection != NULL); - dbus_mutex_lock (connection->mutex); + CONNECTION_LOCK (connection); _dbus_transport_set_max_received_size (connection->transport, size); - dbus_mutex_unlock (connection->mutex); + CONNECTION_UNLOCK (connection); } /** @@ -3032,9 +3069,9 @@ dbus_connection_get_max_received_size (DBusConnection *connection) _dbus_return_val_if_fail (connection != NULL, 0); - dbus_mutex_lock (connection->mutex); + CONNECTION_LOCK (connection); res = _dbus_transport_get_max_received_size (connection->transport); - dbus_mutex_unlock (connection->mutex); + CONNECTION_UNLOCK (connection); return res; } @@ -3055,9 +3092,9 @@ dbus_connection_get_outgoing_size (DBusConnection *connection) _dbus_return_val_if_fail (connection != NULL, 0); - dbus_mutex_lock (connection->mutex); + CONNECTION_LOCK (connection); res = _dbus_counter_get_value (connection->outgoing_counter); - dbus_mutex_unlock (connection->mutex); + CONNECTION_UNLOCK (connection); return res; } diff --git a/dbus/dbus-internals.c b/dbus/dbus-internals.c index 25bd52ba..6a091e62 100644 --- a/dbus/dbus-internals.c +++ b/dbus/dbus-internals.c @@ -190,7 +190,6 @@ _dbus_verbose_real (const char *format, { va_list args; static dbus_bool_t verbose = TRUE; - static unsigned long pid; /* things are written a bit oddly here so that * in the non-verbose case we just have the one @@ -202,13 +201,12 @@ _dbus_verbose_real (const char *format, if (!verbose_initted) { verbose = _dbus_getenv ("DBUS_VERBOSE") != NULL; - pid = _dbus_getpid (); verbose_initted = TRUE; if (!verbose) return; } - fprintf (stderr, "%lu: ", pid); + fprintf (stderr, "%lu: ", _dbus_getpid ()); va_start (args, format); vfprintf (stderr, format, args); diff --git a/dbus/dbus-message.c b/dbus/dbus-message.c index 668736dc..29209106 100644 --- a/dbus/dbus-message.c +++ b/dbus/dbus-message.c @@ -81,7 +81,7 @@ typedef struct */ struct DBusMessage { - dbus_atomic_t refcount; /**< Reference count */ + volatile dbus_atomic_t refcount; /**< Reference count */ DBusString header; /**< Header network data, stored * separately from body so we can @@ -1134,7 +1134,7 @@ dbus_message_copy (const DBusMessage *message) void dbus_message_ref (DBusMessage *message) { - dbus_atomic_t refcount; + volatile dbus_atomic_t refcount; _dbus_return_if_fail (message != NULL); @@ -1163,7 +1163,7 @@ free_size_counter (void *element, void dbus_message_unref (DBusMessage *message) { - dbus_atomic_t refcount; + volatile dbus_atomic_t refcount; _dbus_return_if_fail (message != NULL); diff --git a/dbus/dbus-spawn.c b/dbus/dbus-spawn.c index 179b9f9a..d4015561 100644 --- a/dbus/dbus-spawn.c +++ b/dbus/dbus-spawn.c @@ -31,6 +31,7 @@ #include #include #include +#include /** * @addtogroup DBusInternalsUtils diff --git a/dbus/dbus-sysdeps.c b/dbus/dbus-sysdeps.c index 91f6e95a..c813a83c 100644 --- a/dbus/dbus-sysdeps.c +++ b/dbus/dbus-sysdeps.c @@ -1790,9 +1790,25 @@ _dbus_getgid (void) return getgid (); } - _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) +{ + register dbus_atomic_t result; + + __asm__ __volatile__ ("lock; xaddl %0,%1" + : "=r" (result), "=m" (*atomic) + : "0" (val), "m" (*atomic)); + return result; +} +#endif + /** * Atomically increments an integer * @@ -1802,8 +1818,11 @@ _DBUS_DEFINE_GLOBAL_LOCK (atomic); * @todo implement arch-specific faster atomic ops */ dbus_atomic_t -_dbus_atomic_inc (dbus_atomic_t *atomic) +_dbus_atomic_inc (volatile dbus_atomic_t *atomic) { +#ifdef DBUS_USE_ATOMIC_INT_486 + return atomic_exchange_and_add (atomic, 1); +#else dbus_atomic_t res; _DBUS_LOCK (atomic); @@ -1811,6 +1830,7 @@ _dbus_atomic_inc (dbus_atomic_t *atomic) res = *atomic; _DBUS_UNLOCK (atomic); return res; +#endif } /** @@ -1822,8 +1842,11 @@ _dbus_atomic_inc (dbus_atomic_t *atomic) * @todo implement arch-specific faster atomic ops */ dbus_atomic_t -_dbus_atomic_dec (dbus_atomic_t *atomic) +_dbus_atomic_dec (volatile dbus_atomic_t *atomic) { +#ifdef DBUS_USE_ATOMIC_INT_486 + return atomic_exchange_and_add (atomic, -1); +#else dbus_atomic_t res; _DBUS_LOCK (atomic); @@ -1831,6 +1854,7 @@ _dbus_atomic_dec (dbus_atomic_t *atomic) res = *atomic; _DBUS_UNLOCK (atomic); return res; +#endif } /** diff --git a/dbus/dbus-sysdeps.h b/dbus/dbus-sysdeps.h index 593496c0..2ae455b1 100644 --- a/dbus/dbus-sysdeps.h +++ b/dbus/dbus-sysdeps.h @@ -169,10 +169,10 @@ unsigned long _dbus_getpid (void); dbus_uid_t _dbus_getuid (void); dbus_gid_t _dbus_getgid (void); -typedef int dbus_atomic_t; +typedef dbus_int32_t dbus_atomic_t; -dbus_atomic_t _dbus_atomic_inc (dbus_atomic_t *atomic); -dbus_atomic_t _dbus_atomic_dec (dbus_atomic_t *atomic); +dbus_atomic_t _dbus_atomic_inc (volatile dbus_atomic_t *atomic); +dbus_atomic_t _dbus_atomic_dec (volatile dbus_atomic_t *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-threads.c b/dbus/dbus-threads.c index 07c98973..76b2f194 100644 --- a/dbus/dbus-threads.c +++ b/dbus/dbus-threads.c @@ -458,7 +458,7 @@ dbus_fake_condvar_free (DBusCondVar *cond) static void dbus_fake_condvar_wait (DBusCondVar *cond, - DBusMutex *mutex) + DBusMutex *mutex) { } diff --git a/glib/Makefile.am b/glib/Makefile.am index d9edf6f5..ebdb932f 100644 --- a/glib/Makefile.am +++ b/glib/Makefile.am @@ -13,21 +13,11 @@ libdbus_glib_1_la_SOURCES = \ libdbus_glib_1_la_LIBADD= $(DBUS_GLIB_LIBS) $(top_builddir)/dbus/libdbus-1.la - if DBUS_BUILD_TESTS if HAVE_GLIB_THREADS - THREAD_APPS=test-thread-server test-thread-client -endif - -noinst_PROGRAMS= test-dbus-glib $(THREAD_APPS) - -test_dbus_glib_SOURCES= \ - test-dbus-glib.c - -test_dbus_glib_LDADD= $(top_builddir)/glib/libdbus-glib-1.la +THREAD_APPS=test-thread-server test-thread-client test-profile -if HAVE_GLIB_THREADS test_thread_server_SOURCES= \ test-thread-server.c \ test-thread.h @@ -41,4 +31,25 @@ test_thread_client_SOURCES= \ test_thread_client_LDADD= $(DBUS_GLIB_THREADS_LIBS) $(top_builddir)/glib/libdbus-glib-1.la endif +noinst_PROGRAMS= test-dbus-glib $(THREAD_APPS) + +test_dbus_glib_SOURCES= \ + test-dbus-glib.c + +test_dbus_glib_LDADD= $(top_builddir)/glib/libdbus-glib-1.la + +else +### not building tests + +if HAVE_GLIB_THREADS +noinst_PROGRAMS=test-profile +endif + endif + +if HAVE_GLIB_THREADS +test_profile_SOURCES= \ + test-profile.c + +test_profile_LDADD= $(DBUS_GLIB_THREADS_LIBS) $(top_builddir)/glib/libdbus-glib-1.la +endif \ No newline at end of file diff --git a/glib/test-profile.c b/glib/test-profile.c new file mode 100644 index 00000000..6173f3a5 --- /dev/null +++ b/glib/test-profile.c @@ -0,0 +1,215 @@ +/* -*- mode: C; c-file-style: "gnu" -*- */ +/* test-profile.c Program that does basic message-response for timing + * + * Copyright (C) 2003 Red Hat Inc. + * + * Licensed under the Academic Free License version 1.2 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include "dbus-glib.h" +#include + +#define N_CLIENT_THREADS 1 +#define N_ITERATIONS 2000 +#define ECHO_MESSAGE "org.freedesktop.DBus.Test.EchoProfile" +static const char *address; + +static void +send_echo_message (DBusConnection *connection) +{ + DBusMessage *message; + + message = dbus_message_new (ECHO_MESSAGE, NULL); + dbus_message_append_args (message, + DBUS_TYPE_STRING, "Hello World!", + DBUS_TYPE_INT32, 123456, + DBUS_TYPE_INVALID); + dbus_connection_send (connection, message, NULL); + dbus_message_unref (message); + dbus_connection_flush (connection); +} + +static DBusHandlerResult +client_filter (DBusMessageHandler *handler, + DBusConnection *connection, + DBusMessage *message, + void *user_data) +{ + int *iterations = user_data; + + if (dbus_message_has_name (message, DBUS_MESSAGE_LOCAL_DISCONNECT)) + { + g_printerr ("Client thread disconnected\n"); + exit (1); + } + else if (dbus_message_has_name (message, + ECHO_MESSAGE)) + { + *iterations += 1; + send_echo_message (connection); + if (*iterations > N_ITERATIONS) + { + g_print ("Completed %d iterations\n", N_ITERATIONS); + exit (0); + } + } + + return DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS; +} + +static void* +thread_func (void *data) +{ + DBusError error; + GMainContext *context; + GMainLoop *loop; + DBusMessageHandler *handler; + DBusConnection *connection; + int iterations; + + g_printerr ("Starting client thread\n"); + + dbus_error_init (&error); + connection = dbus_connection_open (address, &error); + if (connection == NULL) + { + g_printerr ("could not open connection: %s\n", error.message); + dbus_error_free (&error); + exit (1); + } + + iterations = 0; + + handler = dbus_message_handler_new (client_filter, + &iterations, NULL); + + if (!dbus_connection_add_filter (connection, + handler)) + g_error ("no memory"); + + /* FIXME we leak the handler */ + + context = g_main_context_new (); + loop = g_main_loop_new (context, FALSE); + + dbus_connection_setup_with_g_main (connection, context); + + g_printerr ("Client thread sending message to prime pingpong\n"); + send_echo_message (connection); + g_printerr ("Client thread sent message\n"); + + g_printerr ("Client thread entering main loop\n"); + g_main_loop_run (loop); + g_printerr ("Client thread exiting main loop\n"); + + g_main_loop_unref (loop); + g_main_context_unref (context); + + return NULL; +} + +static DBusHandlerResult +server_filter (DBusMessageHandler *handler, + DBusConnection *connection, + DBusMessage *message, + void *user_data) +{ + if (dbus_message_has_name (message, DBUS_MESSAGE_LOCAL_DISCONNECT)) + { + g_printerr ("Server thread disconnected\n"); + exit (1); + } + else if (dbus_message_has_name (message, + ECHO_MESSAGE)) + { + send_echo_message (connection); + } + + return DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS; +} + +static void +new_connection_callback (DBusServer *server, + DBusConnection *new_connection, + void *user_data) +{ + DBusMessageHandler *handler; + + dbus_connection_ref (new_connection); + dbus_connection_setup_with_g_main (new_connection, NULL); + + handler = dbus_message_handler_new (server_filter, + NULL, NULL); + + if (!dbus_connection_add_filter (new_connection, + handler)) + g_error ("no memory"); + + + /* FIXME we leak the handler */ +} + +int +main (int argc, char *argv[]) +{ + GMainLoop *loop; + DBusError error; + DBusServer *server; + int i; + + g_thread_init (NULL); + dbus_gthread_init (); + + dbus_error_init (&error); + server = dbus_server_listen ("unix:tmpdir="DBUS_TEST_SOCKET_DIR, + &error); + if (server == NULL) + { + g_printerr ("Could not start server: %s\n", + error.message); + return 1; + } + + address = dbus_server_get_address (server); + + dbus_server_set_new_connection_function (server, + new_connection_callback, + NULL, NULL); + + loop = g_main_loop_new (NULL, FALSE); + + dbus_server_setup_with_g_main (server, NULL); + + for (i = 0; i < N_CLIENT_THREADS; i++) + { + g_thread_create (thread_func, NULL, FALSE, NULL); + } + + g_printerr ("Server thread entering main loop\n"); + g_main_loop_run (loop); + g_printerr ("Server thread exiting main loop\n"); + + dbus_server_unref (server); + + g_main_loop_unref (loop); + + return 0; +} + -- cgit