diff options
author | Havoc Pennington <hp@redhat.com> | 2005-02-13 17:16:25 +0000 |
---|---|---|
committer | Havoc Pennington <hp@redhat.com> | 2005-02-13 17:16:25 +0000 |
commit | f349e6b8c50ea6faa48c8261198cf1b07bf59a79 (patch) | |
tree | 80661925d7864c5772e3c5999c131a068ea549e4 | |
parent | 970be5fda36ea575973a9e7f25389e2ef173b940 (diff) |
2005-02-13 Havoc Pennington <hp@redhat.com>
* dbus/dbus-object-tree.c (handle_default_introspect_and_unlock):
fix a double-unlock
* dbus/dbus-connection.c
(_dbus_connection_detach_pending_call_unlocked): add this
Initial semi-correct pass through to fix thread locking; there are
still some issues with the condition variable paths I'm pretty
sure
* dbus/dbus-server.c: add a mutex on DBusServer and appropriate
lock/unlock calls
* dbus/dbus-connection.c (_dbus_connection_do_iteration_unlocked):
rename to add _unlocked
(struct DBusConnection): move "dispatch_acquired" and
"io_path_acquired" to use only one bit each.
(CONNECTION_LOCK, CONNECTION_UNLOCK): add checks with !DBUS_DISABLE_CHECKS
(dbus_connection_set_watch_functions): hacky fix to reentrancy
(_dbus_connection_add_watch, _dbus_connection_remove_watch)
(_dbus_connection_toggle_watch, _dbus_connection_add_timeout)
(_dbus_connection_remove_timeout)
(_dbus_connection_toggle_timeout): drop lock when calling out to
user functions; done in a hacky/bad way.
(_dbus_connection_send_and_unlock): add a missing unlock
(_dbus_connection_block_for_reply): add a missing unlock
* dbus/dbus-transport.c (_dbus_transport_get_is_authenticated):
drop lock in a hacky probably unsafe way to call out to user
function
-rw-r--r-- | ChangeLog | 33 | ||||
-rw-r--r-- | configure.in | 3 | ||||
-rw-r--r-- | dbus/dbus-connection-internal.h | 2 | ||||
-rw-r--r-- | dbus/dbus-connection.c | 461 | ||||
-rw-r--r-- | dbus/dbus-object-tree.c | 45 | ||||
-rw-r--r-- | dbus/dbus-server-protected.h | 39 | ||||
-rw-r--r-- | dbus/dbus-server-unix.c | 55 | ||||
-rw-r--r-- | dbus/dbus-server.c | 197 | ||||
-rw-r--r-- | dbus/dbus-transport-unix.c | 18 | ||||
-rw-r--r-- | dbus/dbus-transport.c | 59 | ||||
-rw-r--r-- | doc/TODO | 2 | ||||
-rw-r--r-- | tools/Makefile.am | 4 | ||||
-rw-r--r-- | tools/dbus-tree-view.c | 2 | ||||
-rw-r--r-- | tools/dbus-viewer.c | 189 |
14 files changed, 886 insertions, 223 deletions
@@ -1,3 +1,36 @@ +2005-02-13 Havoc Pennington <hp@redhat.com> + + * dbus/dbus-object-tree.c (handle_default_introspect_and_unlock): + fix a double-unlock + + * dbus/dbus-connection.c + (_dbus_connection_detach_pending_call_unlocked): add this + + Initial semi-correct pass through to fix thread locking; there are + still some issues with the condition variable paths I'm pretty + sure + + * dbus/dbus-server.c: add a mutex on DBusServer and appropriate + lock/unlock calls + + * dbus/dbus-connection.c (_dbus_connection_do_iteration_unlocked): + rename to add _unlocked + (struct DBusConnection): move "dispatch_acquired" and + "io_path_acquired" to use only one bit each. + (CONNECTION_LOCK, CONNECTION_UNLOCK): add checks with !DBUS_DISABLE_CHECKS + (dbus_connection_set_watch_functions): hacky fix to reentrancy + (_dbus_connection_add_watch, _dbus_connection_remove_watch) + (_dbus_connection_toggle_watch, _dbus_connection_add_timeout) + (_dbus_connection_remove_timeout) + (_dbus_connection_toggle_timeout): drop lock when calling out to + user functions; done in a hacky/bad way. + (_dbus_connection_send_and_unlock): add a missing unlock + (_dbus_connection_block_for_reply): add a missing unlock + + * dbus/dbus-transport.c (_dbus_transport_get_is_authenticated): + drop lock in a hacky probably unsafe way to call out to user + function + 2005-02-12 Havoc Pennington <hp@redhat.com> * tools/dbus-tree-view.c (info_set_func_text): display more diff --git a/configure.in b/configure.in index 87f214b1..0e76921b 100644 --- a/configure.in +++ b/configure.in @@ -842,6 +842,7 @@ if test x$have_glib = xno ; then have_gtk=no else PKG_CHECK_MODULES(DBUS_GTK, gtk+-2.0, have_gtk=yes, have_gtk=no) + PKG_CHECK_MODULES(DBUS_GTK_THREADS, gtk+-2.0 gthread-2.0, have_gtk_threads=yes, have_gtk_threads=no) fi if test x$have_gtk = xno ; then @@ -863,6 +864,8 @@ AM_CONDITIONAL(HAVE_GTK, test x$have_gtk = xyes) dnl Gtk flags AC_SUBST(DBUS_GTK_CFLAGS) AC_SUBST(DBUS_GTK_LIBS) +AC_SUBST(DBUS_GTK_THREADS_CFLAGS) +AC_SUBST(DBUS_GTK_THREADS_LIBS) # Qt detection AC_PATH_PROG(QT_MOC, moc, no) diff --git a/dbus/dbus-connection-internal.h b/dbus/dbus-connection-internal.h index 21dc415f..57e6fb0d 100644 --- a/dbus/dbus-connection-internal.h +++ b/dbus/dbus-connection-internal.h @@ -74,7 +74,7 @@ void _dbus_connection_toggle_timeout (DBusConnection DBusTimeout *timeout, dbus_bool_t enabled); DBusConnection* _dbus_connection_new_for_transport (DBusTransport *transport); -void _dbus_connection_do_iteration (DBusConnection *connection, +void _dbus_connection_do_iteration_unlocked (DBusConnection *connection, unsigned int flags, int timeout_milliseconds); diff --git a/dbus/dbus-connection.c b/dbus/dbus-connection.c index dfc5d44b..cac4fc8c 100644 --- a/dbus/dbus-connection.c +++ b/dbus/dbus-connection.c @@ -1,7 +1,7 @@ /* -*- mode: C; c-file-style: "gnu" -*- */ /* dbus-connection.c DBusConnection object * - * Copyright (C) 2002, 2003, 2004 Red Hat Inc. + * Copyright (C) 2002, 2003, 2004, 2005 Red Hat Inc. * * Licensed under the Academic Free License version 2.1 * @@ -39,20 +39,37 @@ #include "dbus-pending-call.h" #include "dbus-object-tree.h" -#if 0 -#define CONNECTION_LOCK(connection) do { \ - _dbus_verbose (" LOCK: %s\n", _DBUS_FUNCTION_NAME); \ - dbus_mutex_lock ((connection)->mutex); \ +#ifdef DBUS_DISABLE_CHECKS +#define TOOK_LOCK_CHECK(connection) +#define RELEASING_LOCK_CHECK(connection) +#define HAVE_LOCK_CHECK(connection) +#else +#define TOOK_LOCK_CHECK(connection) do { \ + _dbus_assert (!(connection)->have_connection_lock); \ + (connection)->have_connection_lock = TRUE; \ } while (0) -#define CONNECTION_UNLOCK(connection) do { \ - _dbus_verbose (" UNLOCK: %s\n", _DBUS_FUNCTION_NAME); \ - dbus_mutex_unlock ((connection)->mutex); \ +#define RELEASING_LOCK_CHECK(connection) do { \ + _dbus_assert ((connection)->have_connection_lock); \ + (connection)->have_connection_lock = FALSE; \ } while (0) -#else -#define CONNECTION_LOCK(connection) dbus_mutex_lock ((connection)->mutex) -#define CONNECTION_UNLOCK(connection) dbus_mutex_unlock ((connection)->mutex) +#define HAVE_LOCK_CHECK(connection) _dbus_assert ((connection)->have_connection_lock) +/* A "DO_NOT_HAVE_LOCK_CHECK" is impossible since we need the lock to check the flag */ #endif +#define TRACE_LOCKS 1 + +#define CONNECTION_LOCK(connection) do { \ + if (TRACE_LOCKS) { _dbus_verbose (" LOCK: %s\n", _DBUS_FUNCTION_NAME); } \ + dbus_mutex_lock ((connection)->mutex); \ + TOOK_LOCK_CHECK (connection); \ + } while (0) + +#define CONNECTION_UNLOCK(connection) do { \ + if (TRACE_LOCKS) { _dbus_verbose (" UNLOCK: %s\n", _DBUS_FUNCTION_NAME); } \ + RELEASING_LOCK_CHECK (connection); \ + dbus_mutex_unlock ((connection)->mutex); \ + } while (0) + #define DISPATCH_STATUS_NAME(s) \ ((s) == DBUS_DISPATCH_COMPLETE ? "complete" : \ (s) == DBUS_DISPATCH_DATA_REMAINS ? "data remains" : \ @@ -171,10 +188,7 @@ struct DBusConnection DBusMutex *mutex; /**< Lock on the entire DBusConnection */ - dbus_bool_t dispatch_acquired; /**< Protects dispatch() */ DBusCondVar *dispatch_cond; /**< Protects dispatch() */ - - dbus_bool_t io_path_acquired; /**< Protects transport io path */ DBusCondVar *io_path_cond; /**< Protects transport io path */ DBusList *outgoing_messages; /**< Queue of messages we need to send, send the end of the list first. */ @@ -215,9 +229,16 @@ struct DBusConnection * for the global linked list mempool lock */ DBusObjectTree *objects; /**< Object path handlers registered with this connection */ - + + unsigned int dispatch_acquired : 1; /**< Someone has dispatch path */ + unsigned int io_path_acquired : 1; /**< Someone has transport io path */ + unsigned int exit_on_disconnect : 1; /**< If #TRUE, exit after handling disconnect signal */ - + +#ifndef DBUS_DISABLE_CHECKS + unsigned int have_connection_lock : 1; /**< Used to check locking */ +#endif + #ifndef DBUS_DISABLE_CHECKS int generation; /**< _dbus_current_generation that should correspond to this connection */ #endif @@ -387,6 +408,8 @@ static void _dbus_connection_queue_synthesized_message_link (DBusConnection *connection, DBusList *link) { + HAVE_LOCK_CHECK (connection); + _dbus_list_append_link (&connection->incoming_messages, link); connection->n_incoming += 1; @@ -408,6 +431,7 @@ _dbus_connection_queue_synthesized_message_link (DBusConnection *connection, dbus_bool_t _dbus_connection_has_messages_to_send_unlocked (DBusConnection *connection) { + HAVE_LOCK_CHECK (connection); return connection->outgoing_messages != NULL; } @@ -441,6 +465,8 @@ dbus_connection_has_messages_to_send (DBusConnection *connection) DBusMessage* _dbus_connection_get_message_to_send (DBusConnection *connection) { + HAVE_LOCK_CHECK (connection); + return _dbus_list_get_last (&connection->outgoing_messages); } @@ -458,6 +484,8 @@ _dbus_connection_message_sent (DBusConnection *connection, { DBusList *link; + HAVE_LOCK_CHECK (connection); + /* This can be called before we even complete authentication, since * it's called on disconnect to clean up the outgoing queue. * It's also called as we successfully send each message. @@ -495,6 +523,62 @@ _dbus_connection_message_sent (DBusConnection *connection, dbus_message_unref (message); } +typedef dbus_bool_t (* DBusWatchAddFunction) (DBusWatchList *list, + DBusWatch *watch); +typedef void (* DBusWatchRemoveFunction) (DBusWatchList *list, + DBusWatch *watch); +typedef void (* DBusWatchToggleFunction) (DBusWatchList *list, + DBusWatch *watch, + dbus_bool_t enabled); + +static dbus_bool_t +protected_change_watch (DBusConnection *connection, + DBusWatch *watch, + DBusWatchAddFunction add_function, + DBusWatchRemoveFunction remove_function, + DBusWatchToggleFunction toggle_function, + dbus_bool_t enabled) +{ + DBusWatchList *watches; + dbus_bool_t retval; + + HAVE_LOCK_CHECK (connection); + + /* This isn't really safe or reasonable; a better pattern is the "do everything, then + * drop lock and call out" one; but it has to be propagated up through all callers + */ + + watches = connection->watches; + if (watches) + { + connection->watches = NULL; + _dbus_connection_ref_unlocked (connection); + CONNECTION_UNLOCK (connection); + + if (add_function) + retval = (* add_function) (watches, watch); + else if (remove_function) + { + retval = TRUE; + (* remove_function) (watches, watch); + } + else + { + retval = TRUE; + (* toggle_function) (watches, watch, enabled); + } + + CONNECTION_LOCK (connection); + connection->watches = watches; + _dbus_connection_unref_unlocked (connection); + + return retval; + } + else + return FALSE; +} + + /** * Adds a watch using the connection's DBusAddWatchFunction if * available. Otherwise records the watch to be added when said @@ -509,11 +593,9 @@ dbus_bool_t _dbus_connection_add_watch (DBusConnection *connection, DBusWatch *watch) { - if (connection->watches) /* null during finalize */ - return _dbus_watch_list_add_watch (connection->watches, - watch); - else - return FALSE; + return protected_change_watch (connection, watch, + _dbus_watch_list_add_watch, + NULL, NULL, FALSE); } /** @@ -528,9 +610,10 @@ void _dbus_connection_remove_watch (DBusConnection *connection, DBusWatch *watch) { - if (connection->watches) /* null during finalize */ - _dbus_watch_list_remove_watch (connection->watches, - watch); + protected_change_watch (connection, watch, + NULL, + _dbus_watch_list_remove_watch, + NULL, FALSE); } /** @@ -549,10 +632,66 @@ _dbus_connection_toggle_watch (DBusConnection *connection, dbus_bool_t enabled) { _dbus_assert (watch != NULL); + + protected_change_watch (connection, watch, + NULL, NULL, + _dbus_watch_list_toggle_watch, + enabled); +} + +typedef dbus_bool_t (* DBusTimeoutAddFunction) (DBusTimeoutList *list, + DBusTimeout *timeout); +typedef void (* DBusTimeoutRemoveFunction) (DBusTimeoutList *list, + DBusTimeout *timeout); +typedef void (* DBusTimeoutToggleFunction) (DBusTimeoutList *list, + DBusTimeout *timeout, + dbus_bool_t enabled); + +static dbus_bool_t +protected_change_timeout (DBusConnection *connection, + DBusTimeout *timeout, + DBusTimeoutAddFunction add_function, + DBusTimeoutRemoveFunction remove_function, + DBusTimeoutToggleFunction toggle_function, + dbus_bool_t enabled) +{ + DBusTimeoutList *timeouts; + dbus_bool_t retval; + + HAVE_LOCK_CHECK (connection); + + /* This isn't really safe or reasonable; a better pattern is the "do everything, then + * drop lock and call out" one; but it has to be propagated up through all callers + */ - if (connection->watches) /* null during finalize */ - _dbus_watch_list_toggle_watch (connection->watches, - watch, enabled); + timeouts = connection->timeouts; + if (timeouts) + { + connection->timeouts = NULL; + _dbus_connection_ref_unlocked (connection); + CONNECTION_UNLOCK (connection); + + if (add_function) + retval = (* add_function) (timeouts, timeout); + else if (remove_function) + { + retval = TRUE; + (* remove_function) (timeouts, timeout); + } + else + { + retval = TRUE; + (* toggle_function) (timeouts, timeout, enabled); + } + + CONNECTION_LOCK (connection); + connection->timeouts = timeouts; + _dbus_connection_unref_unlocked (connection); + + return retval; + } + else + return FALSE; } /** @@ -570,11 +709,9 @@ dbus_bool_t _dbus_connection_add_timeout (DBusConnection *connection, DBusTimeout *timeout) { - if (connection->timeouts) /* null during finalize */ - return _dbus_timeout_list_add_timeout (connection->timeouts, - timeout); - else - return FALSE; + return protected_change_timeout (connection, timeout, + _dbus_timeout_list_add_timeout, + NULL, NULL, FALSE); } /** @@ -589,9 +726,10 @@ void _dbus_connection_remove_timeout (DBusConnection *connection, DBusTimeout *timeout) { - if (connection->timeouts) /* null during finalize */ - _dbus_timeout_list_remove_timeout (connection->timeouts, - timeout); + protected_change_timeout (connection, timeout, + NULL, + _dbus_timeout_list_remove_timeout, + NULL, FALSE); } /** @@ -604,19 +742,22 @@ _dbus_connection_remove_timeout (DBusConnection *connection, * @param enabled whether to enable or disable */ void -_dbus_connection_toggle_timeout (DBusConnection *connection, +_dbus_connection_toggle_timeout (DBusConnection *connection, DBusTimeout *timeout, - dbus_bool_t enabled) + dbus_bool_t enabled) { - if (connection->timeouts) /* null during finalize */ - _dbus_timeout_list_toggle_timeout (connection->timeouts, - timeout, enabled); + protected_change_timeout (connection, timeout, + NULL, NULL, + _dbus_timeout_list_toggle_timeout, + enabled); } static dbus_bool_t _dbus_connection_attach_pending_call_unlocked (DBusConnection *connection, DBusPendingCall *pending) { + HAVE_LOCK_CHECK (connection); + _dbus_assert (pending->reply_serial != 0); if (!_dbus_connection_add_timeout (connection, pending->timeout)) @@ -627,6 +768,8 @@ _dbus_connection_attach_pending_call_unlocked (DBusConnection *connection, pending)) { _dbus_connection_remove_timeout (connection, pending->timeout); + + HAVE_LOCK_CHECK (connection); return FALSE; } @@ -634,6 +777,8 @@ _dbus_connection_attach_pending_call_unlocked (DBusConnection *connection, pending->connection = connection; dbus_pending_call_ref (pending); + + HAVE_LOCK_CHECK (connection); return TRUE; } @@ -664,6 +809,19 @@ free_pending_call_on_hash_removal (void *data) } static void +_dbus_connection_detach_pending_call_unlocked (DBusConnection *connection, + DBusPendingCall *pending) +{ + /* Can't have a destroy notifier on the pending call if we're going to do this */ + + dbus_pending_call_ref (pending); + _dbus_hash_table_remove_int (connection->pending_replies, + pending->reply_serial); + _dbus_assert (pending->connection == NULL); + dbus_pending_call_unref (pending); +} + +static void _dbus_connection_detach_pending_call_and_unlock (DBusConnection *connection, DBusPendingCall *pending) { @@ -674,6 +832,7 @@ _dbus_connection_detach_pending_call_and_unlock (DBusConnection *connection, dbus_pending_call_ref (pending); _dbus_hash_table_remove_int (connection->pending_replies, pending->reply_serial); + _dbus_assert (pending->connection == NULL); CONNECTION_UNLOCK (connection); dbus_pending_call_unref (pending); } @@ -749,14 +908,25 @@ _dbus_connection_acquire_io_path (DBusConnection *connection, { dbus_bool_t res = TRUE; + _dbus_verbose ("%s start connection->io_path_acquired = %d timeout = %d\n", + _DBUS_FUNCTION_NAME, connection->io_path_acquired, timeout_milliseconds); + if (connection->io_path_acquired) { +#ifndef DBUS_DISABLE_CHECKS + connection->have_connection_lock = FALSE; +#endif + if (timeout_milliseconds != -1) res = dbus_condvar_wait_timeout (connection->io_path_cond, connection->mutex, timeout_milliseconds); else dbus_condvar_wait (connection->io_path_cond, connection->mutex); + +#ifndef DBUS_DISABLE_CHECKS + connection->have_connection_lock = TRUE; +#endif } if (res) @@ -765,6 +935,9 @@ _dbus_connection_acquire_io_path (DBusConnection *connection, connection->io_path_acquired = TRUE; } + + _dbus_verbose ("%s end connection->io_path_acquired = %d res = %d\n", + _DBUS_FUNCTION_NAME, connection->io_path_acquired, res); return res; } @@ -781,6 +954,9 @@ _dbus_connection_release_io_path (DBusConnection *connection) { _dbus_assert (connection->io_path_acquired); + _dbus_verbose ("%s start connection->io_path_acquired = %d\n", + _DBUS_FUNCTION_NAME, connection->io_path_acquired); + connection->io_path_acquired = FALSE; dbus_condvar_wake_one (connection->io_path_cond); } @@ -789,7 +965,7 @@ _dbus_connection_release_io_path (DBusConnection *connection) /** * Queues incoming messages and sends outgoing messages for this * connection, optionally blocking in the process. Each call to - * _dbus_connection_do_iteration() will call select() or poll() one + * _dbus_connection_do_iteration_unlocked() will call select() or poll() one * time and then read or write data if possible. * * The purpose of this function is to be able to flush outgoing @@ -815,10 +991,14 @@ _dbus_connection_release_io_path (DBusConnection *connection) * @param timeout_milliseconds maximum blocking time, or -1 for no limit. */ void -_dbus_connection_do_iteration (DBusConnection *connection, - unsigned int flags, - int timeout_milliseconds) +_dbus_connection_do_iteration_unlocked (DBusConnection *connection, + unsigned int flags, + int timeout_milliseconds) { + _dbus_verbose ("%s start\n", _DBUS_FUNCTION_NAME); + + HAVE_LOCK_CHECK (connection); + if (connection->n_outgoing == 0) flags &= ~DBUS_ITERATION_DO_WRITING; @@ -829,6 +1009,8 @@ _dbus_connection_do_iteration (DBusConnection *connection, flags, timeout_milliseconds); _dbus_connection_release_io_path (connection); } + + _dbus_verbose ("%s end\n", _DBUS_FUNCTION_NAME); } /** @@ -949,11 +1131,15 @@ _dbus_connection_new_for_transport (DBusTransport *transport) connection->client_serial = 1; connection->disconnect_message_link = disconnect_link; + + CONNECTION_LOCK (connection); if (!_dbus_transport_set_connection (transport, connection)) goto error; - _dbus_transport_ref (transport); + _dbus_transport_ref (transport); + + CONNECTION_UNLOCK (connection); return connection; @@ -1006,9 +1192,11 @@ _dbus_connection_new_for_transport (DBusTransport *transport) */ DBusConnection * _dbus_connection_ref_unlocked (DBusConnection *connection) -{ +{ _dbus_assert (connection != NULL); _dbus_assert (connection->generation == _dbus_current_generation); + + HAVE_LOCK_CHECK (connection); #ifdef DBUS_HAVE_ATOMIC_INT _dbus_atomic_inc (&connection->refcount); @@ -1031,7 +1219,9 @@ _dbus_connection_unref_unlocked (DBusConnection *connection) { dbus_bool_t last_unref; - _dbus_return_if_fail (connection != NULL); + HAVE_LOCK_CHECK (connection); + + _dbus_assert (connection != NULL); /* The connection lock is better than the global * lock in the atomic increment fallback @@ -1089,6 +1279,8 @@ _dbus_connection_handle_watch (DBusWatch *watch, DBusDispatchStatus status; connection = data; + + _dbus_verbose ("%s start\n", _DBUS_FUNCTION_NAME); CONNECTION_LOCK (connection); _dbus_connection_acquire_io_path (connection, -1); @@ -1096,10 +1288,16 @@ _dbus_connection_handle_watch (DBusWatch *watch, watch, condition); _dbus_connection_release_io_path (connection); + HAVE_LOCK_CHECK (connection); + + _dbus_verbose ("%s middle\n", _DBUS_FUNCTION_NAME); + status = _dbus_connection_get_dispatch_status_unlocked (connection); /* this calls out to user code */ _dbus_connection_update_dispatch_status_and_unlock (connection, status); + + _dbus_verbose ("%s end\n", _DBUS_FUNCTION_NAME); return retval; } @@ -1154,7 +1352,10 @@ dbus_connection_open (const char *address, dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); return NULL; } - + +#ifndef DBUS_DISABLE_CHECKS + _dbus_assert (!connection->have_connection_lock); +#endif return connection; } @@ -1357,7 +1558,8 @@ dbus_connection_disconnect (DBusConnection *connection) CONNECTION_LOCK (connection); _dbus_transport_disconnect (connection->transport); - + + _dbus_verbose ("%s middle\n", _DBUS_FUNCTION_NAME); status = _dbus_connection_get_dispatch_status_unlocked (connection); /* this calls out to user code */ @@ -1367,6 +1569,7 @@ dbus_connection_disconnect (DBusConnection *connection) static dbus_bool_t _dbus_connection_get_is_connected_unlocked (DBusConnection *connection) { + HAVE_LOCK_CHECK (connection); return _dbus_transport_get_is_connected (connection->transport); } @@ -1445,6 +1648,8 @@ _dbus_connection_preallocate_send_unlocked (DBusConnection *connection) { DBusPreallocatedSend *preallocated; + HAVE_LOCK_CHECK (connection); + _dbus_assert (connection != NULL); preallocated = dbus_new (DBusPreallocatedSend, 1); @@ -1604,9 +1809,9 @@ _dbus_connection_send_preallocated_unlocked_no_update (DBusConnection *con /* Now we need to run an iteration to hopefully just write the messages * out immediately, and otherwise get them queued up */ - _dbus_connection_do_iteration (connection, - DBUS_ITERATION_DO_WRITING, - -1); + _dbus_connection_do_iteration_unlocked (connection, + DBUS_ITERATION_DO_WRITING, + -1); /* If stuff is still queued up, be sure we wake up the main loop */ if (connection->n_outgoing > 0) @@ -1621,10 +1826,13 @@ _dbus_connection_send_preallocated_and_unlock (DBusConnection *connection, { DBusDispatchStatus status; + HAVE_LOCK_CHECK (connection); + _dbus_connection_send_preallocated_unlocked_no_update (connection, preallocated, message, client_serial); + _dbus_verbose ("%s middle\n", _DBUS_FUNCTION_NAME); status = _dbus_connection_get_dispatch_status_unlocked (connection); /* this calls out to user code */ @@ -1699,7 +1907,10 @@ _dbus_connection_send_and_unlock (DBusConnection *connection, preallocated = _dbus_connection_preallocate_send_unlocked (connection); if (preallocated == NULL) - return FALSE; + { + CONNECTION_UNLOCK (connection); + return FALSE; + } _dbus_connection_send_preallocated_and_unlock (connection, preallocated, @@ -1762,6 +1973,7 @@ reply_handler_timeout (void *data) pending->timeout); pending->timeout_added = FALSE; + _dbus_verbose ("%s middle\n", _DBUS_FUNCTION_NAME); status = _dbus_connection_get_dispatch_status_unlocked (connection); /* Unlocks, and calls out to user code */ @@ -1877,8 +2089,12 @@ dbus_connection_send_with_reply (DBusConnection *connection, if (pending_return) *pending_return = pending; else - dbus_pending_call_unref (pending); + { + _dbus_connection_detach_pending_call_unlocked (connection, pending); + dbus_pending_call_unref (pending); + } + _dbus_verbose ("%s middle\n", _DBUS_FUNCTION_NAME); status = _dbus_connection_get_dispatch_status_unlocked (connection); /* this calls out to user code */ @@ -1898,6 +2114,8 @@ check_for_reply_unlocked (DBusConnection *connection, dbus_uint32_t client_serial) { DBusList *link; + + HAVE_LOCK_CHECK (connection); link = _dbus_list_get_first_link (&connection->incoming_messages); @@ -1980,14 +2198,19 @@ _dbus_connection_block_for_reply (DBusConnection *connection, * gets the message before we do? */ /* always block at least once as we know we don't have the reply yet */ - _dbus_connection_do_iteration (connection, - DBUS_ITERATION_DO_READING | - DBUS_ITERATION_BLOCK, - timeout_milliseconds); + _dbus_connection_do_iteration_unlocked (connection, + DBUS_ITERATION_DO_READING | + DBUS_ITERATION_BLOCK, + timeout_milliseconds); recheck_status: + _dbus_verbose ("%s top of recheck\n", _DBUS_FUNCTION_NAME); + + HAVE_LOCK_CHECK (connection); + /* queue messages and get status */ + status = _dbus_connection_get_dispatch_status_unlocked (connection); if (status == DBUS_DISPATCH_DATA_REMAINS) @@ -1996,7 +2219,8 @@ _dbus_connection_block_for_reply (DBusConnection *connection, reply = check_for_reply_unlocked (connection, client_serial); if (reply != NULL) - { + { + _dbus_verbose ("%s checked for reply\n", _DBUS_FUNCTION_NAME); status = _dbus_connection_get_dispatch_status_unlocked (connection); _dbus_verbose ("dbus_connection_send_with_reply_and_block(): got reply\n"); @@ -2011,7 +2235,10 @@ _dbus_connection_block_for_reply (DBusConnection *connection, _dbus_get_current_time (&tv_sec, &tv_usec); if (!_dbus_connection_get_is_connected_unlocked (connection)) - return NULL; + { + CONNECTION_UNLOCK (connection); + return NULL; + } else if (tv_sec < start_tv_sec) _dbus_verbose ("dbus_connection_send_with_reply_and_block(): clock set backward\n"); else if (connection->disconnect_message_link == NULL) @@ -2042,10 +2269,10 @@ _dbus_connection_block_for_reply (DBusConnection *connection, else { /* block again, we don't have the reply buffered yet. */ - _dbus_connection_do_iteration (connection, - DBUS_ITERATION_DO_READING | - DBUS_ITERATION_BLOCK, - timeout_milliseconds); + _dbus_connection_do_iteration_unlocked (connection, + DBUS_ITERATION_DO_READING | + DBUS_ITERATION_BLOCK, + timeout_milliseconds); } goto recheck_status; @@ -2144,16 +2371,25 @@ dbus_connection_flush (DBusConnection *connection) CONNECTION_LOCK (connection); while (connection->n_outgoing > 0 && _dbus_connection_get_is_connected_unlocked (connection)) - _dbus_connection_do_iteration (connection, - DBUS_ITERATION_DO_READING | - DBUS_ITERATION_DO_WRITING | - DBUS_ITERATION_BLOCK, - -1); + { + _dbus_verbose ("doing iteration in %s\n", _DBUS_FUNCTION_NAME); + HAVE_LOCK_CHECK (connection); + _dbus_connection_do_iteration_unlocked (connection, + DBUS_ITERATION_DO_READING | + DBUS_ITERATION_DO_WRITING | + DBUS_ITERATION_BLOCK, + -1); + } + HAVE_LOCK_CHECK (connection); + _dbus_verbose ("%s middle\n", _DBUS_FUNCTION_NAME); status = _dbus_connection_get_dispatch_status_unlocked (connection); + HAVE_LOCK_CHECK (connection); /* Unlocks and calls out to user code */ _dbus_connection_update_dispatch_status_and_unlock (connection, status); + + _dbus_verbose ("%s end\n", _DBUS_FUNCTION_NAME); } /* Call with mutex held. Will drop it while waiting and re-acquire @@ -2165,7 +2401,15 @@ _dbus_connection_wait_for_borrowed (DBusConnection *connection) _dbus_assert (connection->message_borrowed != NULL); while (connection->message_borrowed != NULL) - dbus_condvar_wait (connection->message_returned_cond, connection->mutex); + { +#ifndef DBUS_DISABLE_CHECKS + connection->have_connection_lock = FALSE; +#endif + dbus_condvar_wait (connection->message_returned_cond, connection->mutex); +#ifndef DBUS_DISABLE_CHECKS + connection->have_connection_lock = TRUE; +#endif + } } /** @@ -2191,6 +2435,8 @@ dbus_connection_borrow_message (DBusConnection *connection) _dbus_return_val_if_fail (connection != NULL, NULL); /* can't borrow during dispatch */ _dbus_return_val_if_fail (!connection->dispatch_acquired, NULL); + + _dbus_verbose ("%s start\n", _DBUS_FUNCTION_NAME); /* this is called for the side effect that it queues * up any messages from the transport @@ -2283,6 +2529,8 @@ dbus_connection_steal_borrowed_message (DBusConnection *connection, static DBusList* _dbus_connection_pop_message_link_unlocked (DBusConnection *connection) { + HAVE_LOCK_CHECK (connection); + if (connection->message_borrowed != NULL) _dbus_connection_wait_for_borrowed (connection); @@ -2319,6 +2567,8 @@ static DBusMessage* _dbus_connection_pop_message_unlocked (DBusConnection *connection) { DBusList *link; + + HAVE_LOCK_CHECK (connection); link = _dbus_connection_pop_message_link_unlocked (connection); @@ -2340,6 +2590,8 @@ static void _dbus_connection_putback_message_link_unlocked (DBusConnection *connection, DBusList *message_link) { + HAVE_LOCK_CHECK (connection); + _dbus_assert (message_link != NULL); /* You can't borrow a message while a link is outstanding */ _dbus_assert (connection->message_borrowed == NULL); @@ -2381,6 +2633,8 @@ dbus_connection_pop_message (DBusConnection *connection) DBusMessage *message; DBusDispatchStatus status; + _dbus_verbose ("%s start\n", _DBUS_FUNCTION_NAME); + /* this is called for the side effect that it queues * up any messages from the transport */ @@ -2411,7 +2665,15 @@ static void _dbus_connection_acquire_dispatch (DBusConnection *connection) { if (connection->dispatch_acquired) - dbus_condvar_wait (connection->dispatch_cond, connection->mutex); + { +#ifndef DBUS_DISABLE_CHECKS + connection->have_connection_lock = FALSE; +#endif + dbus_condvar_wait (connection->dispatch_cond, connection->mutex); +#ifndef DBUS_DISABLE_CHECKS + connection->have_connection_lock = TRUE; +#endif + } _dbus_assert (!connection->dispatch_acquired); connection->dispatch_acquired = TRUE; @@ -2445,6 +2707,8 @@ _dbus_connection_failed_pop (DBusConnection *connection, static DBusDispatchStatus _dbus_connection_get_dispatch_status_unlocked (DBusConnection *connection) { + HAVE_LOCK_CHECK (connection); + if (connection->n_incoming > 0) return DBUS_DISPATCH_DATA_REMAINS; else if (!_dbus_transport_queue_messages (connection->transport)) @@ -2511,7 +2775,7 @@ _dbus_connection_update_dispatch_status_and_unlock (DBusConnection *connectio DBusDispatchStatusFunction function; void *data; - /* We have the lock */ + HAVE_LOCK_CHECK (connection); _dbus_connection_ref_unlocked (connection); @@ -2550,6 +2814,8 @@ dbus_connection_get_dispatch_status (DBusConnection *connection) DBusDispatchStatus status; _dbus_return_val_if_fail (connection != NULL, DBUS_DISPATCH_COMPLETE); + + _dbus_verbose ("%s start\n", _DBUS_FUNCTION_NAME); CONNECTION_LOCK (connection); @@ -2759,7 +3025,8 @@ dbus_connection_dispatch (DBusConnection *connection) dbus_message_get_member (message) : "no member", dbus_message_get_signature (message)); - + + HAVE_LOCK_CHECK (connection); result = _dbus_object_tree_dispatch_and_unlock (connection->objects, message); @@ -2874,7 +3141,8 @@ dbus_connection_dispatch (DBusConnection *connection) } _dbus_connection_release_dispatch (connection); - + + _dbus_verbose ("%s before final status update\n", _DBUS_FUNCTION_NAME); status = _dbus_connection_get_dispatch_status_unlocked (connection); /* unlocks and calls user code */ @@ -2952,25 +3220,43 @@ dbus_connection_set_watch_functions (DBusConnection *connection, DBusFreeFunction free_data_function) { dbus_bool_t retval; + DBusWatchList *watches; _dbus_return_val_if_fail (connection != NULL, FALSE); CONNECTION_LOCK (connection); + +#ifndef DBUS_DISABLE_CHECKS + if (connection->watches == NULL) + { + _dbus_warn ("Re-entrant call to %s is not allowed\n", + _DBUS_FUNCTION_NAME); + return FALSE; + } +#endif + /* ref connection for slightly better reentrancy */ _dbus_connection_ref_unlocked (connection); - /* FIXME this can call back into user code, and we need to drop the - * connection lock when it does. + /* This can call back into user code, and we need to drop the + * connection lock when it does. This is kind of a lame + * way to do it. */ - retval = _dbus_watch_list_set_functions (connection->watches, + watches = connection->watches; + connection->watches = NULL; + CONNECTION_UNLOCK (connection); + + retval = _dbus_watch_list_set_functions (watches, add_function, remove_function, toggled_function, data, free_data_function); + CONNECTION_LOCK (connection); + connection->watches = watches; CONNECTION_UNLOCK (connection); /* drop our paranoid refcount */ dbus_connection_unref (connection); - + return retval; } @@ -3016,17 +3302,34 @@ dbus_connection_set_timeout_functions (DBusConnection *connection, DBusFreeFunction free_data_function) { dbus_bool_t retval; + DBusTimeoutList *timeouts; _dbus_return_val_if_fail (connection != NULL, FALSE); CONNECTION_LOCK (connection); + +#ifndef DBUS_DISABLE_CHECKS + if (connection->timeouts == NULL) + { + _dbus_warn ("Re-entrant call to %s is not allowed\n", + _DBUS_FUNCTION_NAME); + return FALSE; + } +#endif + /* ref connection for slightly better reentrancy */ _dbus_connection_ref_unlocked (connection); + + timeouts = connection->timeouts; + connection->timeouts = NULL; + CONNECTION_UNLOCK (connection); - retval = _dbus_timeout_list_set_functions (connection->timeouts, + retval = _dbus_timeout_list_set_functions (timeouts, add_function, remove_function, toggled_function, data, free_data_function); + CONNECTION_LOCK (connection); + connection->timeouts = timeouts; CONNECTION_UNLOCK (connection); /* drop our paranoid refcount */ diff --git a/dbus/dbus-object-tree.c b/dbus/dbus-object-tree.c index ae28cc1c..b693b919 100644 --- a/dbus/dbus-object-tree.c +++ b/dbus/dbus-object-tree.c @@ -1,7 +1,7 @@ /* -*- mode: C; c-file-style: "gnu" -*- */ /* dbus-object-tree.c DBusObjectTree (internals of DBusConnection) * - * Copyright (C) 2003 Red Hat Inc. + * Copyright (C) 2003, 2005 Red Hat Inc. * * Licensed under the Academic Free License version 2.1 * @@ -503,6 +503,7 @@ _dbus_object_tree_unregister_and_unlock (DBusObjectTree *tree, #endif { _dbus_connection_ref_unlocked (connection); + _dbus_verbose ("unlock %s\n", _DBUS_FUNCTION_NAME); _dbus_connection_unlock (connection); } @@ -635,7 +636,10 @@ handle_default_introspect_and_unlock (DBusObjectTree *tree, #ifdef DBUS_BUILD_TESTS if (tree->connection) #endif - _dbus_connection_unlock (tree->connection); + { + _dbus_verbose ("unlock %s %d\n", _DBUS_FUNCTION_NAME, __LINE__); + _dbus_connection_unlock (tree->connection); + } return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } @@ -647,7 +651,10 @@ handle_default_introspect_and_unlock (DBusObjectTree *tree, #ifdef DBUS_BUILD_TESTS if (tree->connection) #endif - _dbus_connection_unlock (tree->connection); + { + _dbus_verbose ("unlock %s %d\n", _DBUS_FUNCTION_NAME, __LINE__); + _dbus_connection_unlock (tree->connection); + } return DBUS_HANDLER_RESULT_NEED_MEMORY; } @@ -690,6 +697,8 @@ handle_default_introspect_and_unlock (DBusObjectTree *tree, if (tree->connection) #endif { + already_unlocked = TRUE; + if (!_dbus_connection_send_and_unlock (tree->connection, reply, NULL)) goto out; } @@ -702,7 +711,10 @@ handle_default_introspect_and_unlock (DBusObjectTree *tree, #endif { if (!already_unlocked) - _dbus_connection_unlock (tree->connection); + { + _dbus_verbose ("unlock %s %d\n", _DBUS_FUNCTION_NAME, __LINE__); + _dbus_connection_unlock (tree->connection); + } } _dbus_string_free (&xml); @@ -747,7 +759,10 @@ _dbus_object_tree_dispatch_and_unlock (DBusObjectTree *tree, #ifdef DBUS_BUILD_TESTS if (tree->connection) #endif - _dbus_connection_unlock (tree->connection); + { + _dbus_verbose ("unlock %s\n", _DBUS_FUNCTION_NAME); + _dbus_connection_unlock (tree->connection); + } _dbus_verbose ("No memory to get decomposed path\n"); @@ -759,7 +774,10 @@ _dbus_object_tree_dispatch_and_unlock (DBusObjectTree *tree, #ifdef DBUS_BUILD_TESTS if (tree->connection) #endif - _dbus_connection_unlock (tree->connection); + { + _dbus_verbose ("unlock %s\n", _DBUS_FUNCTION_NAME); + _dbus_connection_unlock (tree->connection); + } _dbus_verbose ("No path field in message\n"); return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; @@ -822,7 +840,10 @@ _dbus_object_tree_dispatch_and_unlock (DBusObjectTree *tree, #ifdef DBUS_BUILD_TESTS if (tree->connection) #endif - _dbus_connection_unlock (tree->connection); + { + _dbus_verbose ("unlock %s\n", _DBUS_FUNCTION_NAME); + _dbus_connection_unlock (tree->connection); + } /* FIXME you could unregister the subtree in another thread * before we invoke the callback, and I can't figure out a @@ -859,7 +880,10 @@ _dbus_object_tree_dispatch_and_unlock (DBusObjectTree *tree, #ifdef DBUS_BUILD_TESTS if (tree->connection) #endif - _dbus_connection_unlock (tree->connection); + { + _dbus_verbose ("unlock %s\n", _DBUS_FUNCTION_NAME); + _dbus_connection_unlock (tree->connection); + } } while (list != NULL) @@ -993,7 +1017,10 @@ _dbus_object_tree_list_registered_and_unlock (DBusObjectTree *tree, #ifdef DBUS_BUILD_TESTS if (tree->connection) #endif - _dbus_connection_unlock (tree->connection); + { + _dbus_verbose ("unlock %s\n", _DBUS_FUNCTION_NAME); + _dbus_connection_unlock (tree->connection); + } return result; } diff --git a/dbus/dbus-server-protected.h b/dbus/dbus-server-protected.h index bce29ca8..c8aa8601 100644 --- a/dbus/dbus-server-protected.h +++ b/dbus/dbus-server-protected.h @@ -23,6 +23,7 @@ #ifndef DBUS_SERVER_PROTECTED_H #define DBUS_SERVER_PROTECTED_H +#include <config.h> #include <dbus/dbus-internals.h> #include <dbus/dbus-server.h> #include <dbus/dbus-timeout.h> @@ -51,8 +52,9 @@ struct DBusServerVTable */ struct DBusServer { - int refcount; /**< Reference count. */ + DBusAtomic refcount; /**< Reference count. */ const DBusServerVTable *vtable; /**< Virtual methods for this instance. */ + DBusMutex *mutex; /**< Lock on the server object */ DBusWatchList *watches; /**< Our watches */ DBusTimeoutList *timeouts; /**< Our timeouts */ @@ -74,6 +76,10 @@ struct DBusServer char **auth_mechanisms; /**< Array of allowed authentication mechanisms */ unsigned int disconnected : 1; /**< TRUE if we are disconnected. */ + +#ifndef DBUS_DISABLE_CHECKS + unsigned int have_server_lock : 1; /**< Does someone have the server mutex locked */ +#endif }; dbus_bool_t _dbus_server_init_base (DBusServer *server, @@ -95,7 +101,38 @@ void _dbus_server_toggle_timeout (DBusServer *server, DBusTimeout *timeout, dbus_bool_t enabled); +void _dbus_server_ref_unlocked (DBusServer *server); + +#ifdef DBUS_DISABLE_CHECKS +#define TOOK_LOCK_CHECK(server) +#define RELEASING_LOCK_CHECK(server) +#define HAVE_LOCK_CHECK(server) +#else +#define TOOK_LOCK_CHECK(server) do { \ + _dbus_assert (!(server)->have_server_lock); \ + (server)->have_server_lock = TRUE; \ + } while (0) +#define RELEASING_LOCK_CHECK(server) do { \ + _dbus_assert ((server)->have_server_lock); \ + (server)->have_server_lock = FALSE; \ + } while (0) +#define HAVE_LOCK_CHECK(server) _dbus_assert ((server)->have_server_lock) +/* A "DO_NOT_HAVE_LOCK_CHECK" is impossible since we need the lock to check the flag */ +#endif + +#define TRACE_LOCKS 0 + +#define SERVER_LOCK(server) do { \ + if (TRACE_LOCKS) { _dbus_verbose (" LOCK: %s\n", _DBUS_FUNCTION_NAME); } \ + dbus_mutex_lock ((server)->mutex); \ + TOOK_LOCK_CHECK (server); \ + } while (0) +#define SERVER_UNLOCK(server) do { \ + if (TRACE_LOCKS) { _dbus_verbose (" UNLOCK: %s\n", _DBUS_FUNCTION_NAME); } \ + RELEASING_LOCK_CHECK (server); \ + dbus_mutex_unlock ((server)->mutex); \ + } while (0) DBUS_END_DECLS diff --git a/dbus/dbus-server-unix.c b/dbus/dbus-server-unix.c index f576b427..4a07f149 100644 --- a/dbus/dbus-server-unix.c +++ b/dbus/dbus-server-unix.c @@ -72,21 +72,29 @@ unix_finalize (DBusServer *server) */ /* Return value is just for memory, not other failures. */ static dbus_bool_t -handle_new_client_fd (DBusServer *server, - int client_fd) +handle_new_client_fd_and_unlock (DBusServer *server, + int client_fd) { DBusConnection *connection; DBusTransport *transport; + DBusNewConnectionFunction new_connection_function; + void *new_connection_data; _dbus_verbose ("Creating new client connection with fd %d\n", client_fd); - + + HAVE_LOCK_CHECK (server); + if (!_dbus_set_fd_nonblocking (client_fd, NULL)) - return TRUE; + { + SERVER_UNLOCK (server); + return TRUE; + } transport = _dbus_transport_new_for_fd (client_fd, TRUE, NULL); if (transport == NULL) { close (client_fd); + SERVER_UNLOCK (server); return FALSE; } @@ -94,6 +102,7 @@ handle_new_client_fd (DBusServer *server, (const char **) server->auth_mechanisms)) { _dbus_transport_unref (transport); + SERVER_UNLOCK (server); return FALSE; } @@ -103,19 +112,27 @@ handle_new_client_fd (DBusServer *server, connection = _dbus_connection_new_for_transport (transport); _dbus_transport_unref (transport); + transport = NULL; /* now under the connection lock */ if (connection == NULL) - return FALSE; + { + SERVER_UNLOCK (server); + return FALSE; + } - /* See if someone wants to handle this new connection, - * self-referencing for paranoia + /* See if someone wants to handle this new connection, self-referencing + * for paranoia. */ - if (server->new_connection_function) + new_connection_function = server->new_connection_function; + new_connection_data = server->new_connection_data; + + _dbus_server_ref_unlocked (server); + SERVER_UNLOCK (server); + + if (new_connection_function) { - dbus_server_ref (server); - - (* server->new_connection_function) (server, connection, - server->new_connection_data); + (* new_connection_function) (server, connection, + new_connection_data); dbus_server_unref (server); } @@ -133,6 +150,8 @@ unix_handle_watch (DBusWatch *watch, DBusServer *server = data; DBusServerUnix *unix_server = data; + SERVER_LOCK (server); + _dbus_assert (watch == unix_server->watch); _dbus_verbose ("Handling client connection, flags 0x%x\n", flags); @@ -155,12 +174,14 @@ unix_handle_watch (DBusWatch *watch, else _dbus_verbose ("Failed to accept a client connection: %s\n", _dbus_strerror (errno)); + + SERVER_UNLOCK (server); } else { _dbus_fd_set_close_on_exec (client_fd); - if (!handle_new_client_fd (server, client_fd)) + if (!handle_new_client_fd_and_unlock (server, client_fd)) _dbus_verbose ("Rejected client connection due to lack of memory\n"); } } @@ -246,6 +267,10 @@ _dbus_server_new_for_fd (int fd, return NULL; } +#ifndef DBUS_DISABLE_CHECKS + unix_server->base.have_server_lock = TRUE; +#endif + if (!_dbus_server_add_watch (&unix_server->base, watch)) { @@ -254,6 +279,10 @@ _dbus_server_new_for_fd (int fd, dbus_free (unix_server); return NULL; } + +#ifndef DBUS_DISABLE_CHECKS + unix_server->base.have_server_lock = FALSE; +#endif unix_server->fd = fd; unix_server->watch = watch; diff --git a/dbus/dbus-server.c b/dbus/dbus-server.c index 4c706191..788aaad7 100644 --- a/dbus/dbus-server.c +++ b/dbus/dbus-server.c @@ -67,7 +67,7 @@ _dbus_server_init_base (DBusServer *server, const DBusString *address) { server->vtable = vtable; - server->refcount = 1; + server->refcount.value = 1; server->address = NULL; server->watches = NULL; @@ -75,6 +75,10 @@ _dbus_server_init_base (DBusServer *server, if (!_dbus_string_copy_data (address, &server->address)) goto failed; + + server->mutex = dbus_mutex_new (); + if (server->mutex == NULL) + goto failed; server->watches = _dbus_watch_list_new (); if (server->watches == NULL) @@ -91,6 +95,11 @@ _dbus_server_init_base (DBusServer *server, return TRUE; failed: + if (server->mutex) + { + dbus_mutex_free (server->mutex); + server->mutex = NULL; + } if (server->watches) { _dbus_watch_list_free (server->watches); @@ -118,7 +127,7 @@ _dbus_server_init_base (DBusServer *server, */ void _dbus_server_finalize_base (DBusServer *server) -{ +{ /* calls out to application code... */ _dbus_data_slot_list_free (&server->slot_list); @@ -130,6 +139,8 @@ _dbus_server_finalize_base (DBusServer *server) _dbus_watch_list_free (server->watches); _dbus_timeout_list_free (server->timeouts); + dbus_mutex_free (server->mutex); + dbus_free (server->address); dbus_free_string_array (server->auth_mechanisms); @@ -146,6 +157,7 @@ dbus_bool_t _dbus_server_add_watch (DBusServer *server, DBusWatch *watch) { + HAVE_LOCK_CHECK (server); return _dbus_watch_list_add_watch (server->watches, watch); } @@ -159,6 +171,7 @@ void _dbus_server_remove_watch (DBusServer *server, DBusWatch *watch) { + HAVE_LOCK_CHECK (server); _dbus_watch_list_remove_watch (server->watches, watch); } @@ -176,6 +189,8 @@ _dbus_server_toggle_watch (DBusServer *server, DBusWatch *watch, dbus_bool_t enabled) { + HAVE_LOCK_CHECK (server); + if (server->watches) /* null during finalize */ _dbus_watch_list_toggle_watch (server->watches, watch, enabled); @@ -194,6 +209,8 @@ dbus_bool_t _dbus_server_add_timeout (DBusServer *server, DBusTimeout *timeout) { + HAVE_LOCK_CHECK (server); + return _dbus_timeout_list_add_timeout (server->timeouts, timeout); } @@ -207,6 +224,8 @@ void _dbus_server_remove_timeout (DBusServer *server, DBusTimeout *timeout) { + HAVE_LOCK_CHECK (server); + _dbus_timeout_list_remove_timeout (server->timeouts, timeout); } @@ -224,6 +243,8 @@ _dbus_server_toggle_timeout (DBusServer *server, DBusTimeout *timeout, dbus_bool_t enabled) { + HAVE_LOCK_CHECK (server); + if (server->timeouts) /* null during finalize */ _dbus_timeout_list_toggle_timeout (server->timeouts, timeout, enabled); @@ -457,8 +478,16 @@ DBusServer * dbus_server_ref (DBusServer *server) { _dbus_return_val_if_fail (server != NULL, NULL); - - server->refcount += 1; + +#ifdef DBUS_HAVE_ATOMIC_INT + _dbus_atomic_inc (&server->refcount); +#else + SERVER_LOCK (server); + _dbus_assert (server->refcount.value > 0); + + server->refcount.value += 1; + SERVER_UNLOCK (server); +#endif return server; } @@ -474,12 +503,24 @@ dbus_server_ref (DBusServer *server) void dbus_server_unref (DBusServer *server) { + dbus_bool_t last_unref; + _dbus_return_if_fail (server != NULL); - _dbus_assert (server->refcount > 0); +#ifdef DBUS_HAVE_ATOMIC_INT + last_unref = (_dbus_atomic_dec (&server->refcount) == 1); +#else + SERVER_LOCK (server); + + _dbus_assert (server->refcount.value > 0); - server->refcount -= 1; - if (server->refcount == 0) + server->refcount.value -= 1; + last_unref = (server->refcount.value == 0); + + SERVER_UNLOCK (server); +#endif + + if (last_unref) { _dbus_assert (server->vtable->finalize != NULL); @@ -488,6 +529,25 @@ dbus_server_unref (DBusServer *server) } /** + * Like dbus_server_ref() but does not acquire the lock (must already be held) + * + * @param server the server. + */ +void +_dbus_server_ref_unlocked (DBusServer *server) +{ + HAVE_LOCK_CHECK (server); + +#ifdef DBUS_HAVE_ATOMIC_INT + _dbus_atomic_inc (&server->refcount); +#else + _dbus_assert (server->refcount.value > 0); + + server->refcount.value += 1; +#endif +} + +/** * Releases the server's address and stops listening for * new clients. If called more than once, only the first * call has an effect. Does not modify the server's @@ -499,6 +559,8 @@ void dbus_server_disconnect (DBusServer *server) { _dbus_return_if_fail (server != NULL); + + SERVER_LOCK (server); _dbus_assert (server->vtable->disconnect != NULL); @@ -507,6 +569,8 @@ dbus_server_disconnect (DBusServer *server) (* server->vtable->disconnect) (server); server->disconnected = TRUE; + + SERVER_UNLOCK (server); } /** @@ -517,9 +581,15 @@ dbus_server_disconnect (DBusServer *server) dbus_bool_t dbus_server_get_is_connected (DBusServer *server) { - _dbus_return_val_if_fail (server != NULL, FALSE); + dbus_bool_t retval; - return !server->disconnected; + _dbus_return_val_if_fail (server != NULL, FALSE); + + SERVER_LOCK (server); + retval = !server->disconnected; + SERVER_UNLOCK (server); + + return retval; } /** @@ -532,9 +602,15 @@ dbus_server_get_is_connected (DBusServer *server) char* dbus_server_get_address (DBusServer *server) { - _dbus_return_val_if_fail (server != NULL, NULL); + char *retval; - return _dbus_strdup (server->address); + _dbus_return_val_if_fail (server != NULL, NULL); + + SERVER_LOCK (server); + retval = _dbus_strdup (server->address); + SERVER_UNLOCK (server); + + return retval; } /** @@ -555,14 +631,22 @@ dbus_server_set_new_connection_function (DBusServer *server, void *data, DBusFreeFunction free_data_function) { - _dbus_return_if_fail (server != NULL); + DBusFreeFunction old_free_function; + void *old_data; - if (server->new_connection_free_data_function != NULL) - (* server->new_connection_free_data_function) (server->new_connection_data); + _dbus_return_if_fail (server != NULL); + + SERVER_LOCK (server); + old_free_function = server->new_connection_free_data_function; + old_data = server->new_connection_data; server->new_connection_function = function; server->new_connection_data = data; server->new_connection_free_data_function = free_data_function; + SERVER_UNLOCK (server); + + if (old_free_function != NULL) + (* old_free_function) (old_data); } /** @@ -589,14 +673,34 @@ dbus_server_set_watch_functions (DBusServer *server, void *data, DBusFreeFunction free_data_function) { + dbus_bool_t result; + DBusWatchList *watches; + _dbus_return_val_if_fail (server != NULL, FALSE); + + SERVER_LOCK (server); + watches = server->watches; + server->watches = NULL; + if (watches) + { + SERVER_UNLOCK (server); + result = _dbus_watch_list_set_functions (watches, + add_function, + remove_function, + toggled_function, + data, + free_data_function); + SERVER_LOCK (server); + } + else + { + _dbus_warn ("Re-entrant call to %s\n", _DBUS_FUNCTION_NAME); + result = FALSE; + } + server->watches = watches; + SERVER_UNLOCK (server); - return _dbus_watch_list_set_functions (server->watches, - add_function, - remove_function, - toggled_function, - data, - free_data_function); + return result; } /** @@ -622,12 +726,34 @@ dbus_server_set_timeout_functions (DBusServer *server, void *data, DBusFreeFunction free_data_function) { + dbus_bool_t result; + DBusTimeoutList *timeouts; + _dbus_return_val_if_fail (server != NULL, FALSE); + + SERVER_LOCK (server); + timeouts = server->timeouts; + server->timeouts = NULL; + if (timeouts) + { + SERVER_UNLOCK (server); + result = _dbus_timeout_list_set_functions (timeouts, + add_function, + remove_function, + toggled_function, + data, + free_data_function); + SERVER_LOCK (server); + } + else + { + _dbus_warn ("Re-entrant call to %s\n", _DBUS_FUNCTION_NAME); + result = FALSE; + } + server->timeouts = timeouts; + SERVER_UNLOCK (server); - return _dbus_timeout_list_set_functions (server->timeouts, - add_function, remove_function, - toggled_function, - data, free_data_function); + return result; } /** @@ -647,6 +773,8 @@ dbus_server_set_auth_mechanisms (DBusServer *server, char **copy; _dbus_return_val_if_fail (server != NULL, FALSE); + + SERVER_LOCK (server); if (mechanisms != NULL) { @@ -660,6 +788,8 @@ dbus_server_set_auth_mechanisms (DBusServer *server, dbus_free_string_array (server->auth_mechanisms); server->auth_mechanisms = copy; + SERVER_UNLOCK (server); + return TRUE; } @@ -732,19 +862,16 @@ dbus_server_set_data (DBusServer *server, dbus_bool_t retval; _dbus_return_val_if_fail (server != NULL, FALSE); - -#if 0 - dbus_mutex_lock (server->mutex); -#endif + + SERVER_LOCK (server); retval = _dbus_data_slot_list_set (&slot_allocator, &server->slot_list, slot, data, free_data_func, &old_free_func, &old_data); -#if 0 - dbus_mutex_unlock (server->mutex); -#endif + + SERVER_UNLOCK (server); if (retval) { @@ -772,17 +899,13 @@ dbus_server_get_data (DBusServer *server, _dbus_return_val_if_fail (server != NULL, NULL); -#if 0 - dbus_mutex_lock (server->mutex); -#endif + SERVER_LOCK (server); res = _dbus_data_slot_list_get (&slot_allocator, &server->slot_list, slot); -#if 0 - dbus_mutex_unlock (server->mutex); -#endif + SERVER_UNLOCK (server); return res; } diff --git a/dbus/dbus-transport-unix.c b/dbus/dbus-transport-unix.c index 4190da46..2959886a 100644 --- a/dbus/dbus-transport-unix.c +++ b/dbus/dbus-transport-unix.c @@ -70,6 +70,8 @@ static void free_watches (DBusTransport *transport) { DBusTransportUnix *unix_transport = (DBusTransportUnix*) transport; + + _dbus_verbose ("%s start\n", _DBUS_FUNCTION_NAME); if (unix_transport->read_watch) { @@ -90,12 +92,16 @@ free_watches (DBusTransport *transport) _dbus_watch_unref (unix_transport->write_watch); unix_transport->write_watch = NULL; } + + _dbus_verbose ("%s end\n", _DBUS_FUNCTION_NAME); } static void unix_finalize (DBusTransport *transport) { DBusTransportUnix *unix_transport = (DBusTransportUnix*) transport; + + _dbus_verbose ("%s\n", _DBUS_FUNCTION_NAME); free_watches (transport); @@ -871,6 +877,8 @@ static void unix_disconnect (DBusTransport *transport) { DBusTransportUnix *unix_transport = (DBusTransportUnix*) transport; + + _dbus_verbose ("%s\n", _DBUS_FUNCTION_NAME); free_watches (transport); @@ -1004,7 +1012,10 @@ unix_do_iteration (DBusTransport *transport, * by the io_path_cond condvar, so we won't reenter this. */ if (flags & DBUS_ITERATION_BLOCK) - _dbus_connection_unlock (transport->connection); + { + _dbus_verbose ("unlock %s pre poll\n", _DBUS_FUNCTION_NAME); + _dbus_connection_unlock (transport->connection); + } again: poll_res = _dbus_poll (&poll_fd, 1, poll_timeout); @@ -1013,7 +1024,10 @@ unix_do_iteration (DBusTransport *transport, goto again; if (flags & DBUS_ITERATION_BLOCK) - _dbus_connection_lock (transport->connection); + { + _dbus_verbose ("lock %s post poll\n", _DBUS_FUNCTION_NAME); + _dbus_connection_lock (transport->connection); + } if (poll_res >= 0) { diff --git a/dbus/dbus-transport.c b/dbus/dbus-transport.c index 94d4a8a8..c08573d8 100644 --- a/dbus/dbus-transport.c +++ b/dbus/dbus-transport.c @@ -388,10 +388,12 @@ _dbus_transport_unref (DBusTransport *transport) { _dbus_assert (transport != NULL); _dbus_assert (transport->refcount > 0); - + transport->refcount -= 1; if (transport->refcount == 0) { + _dbus_verbose ("%s: finalizing\n", _DBUS_FUNCTION_NAME); + _dbus_assert (transport->vtable->finalize != NULL); (* transport->vtable->finalize) (transport); @@ -409,14 +411,18 @@ _dbus_transport_unref (DBusTransport *transport) void _dbus_transport_disconnect (DBusTransport *transport) { + _dbus_verbose ("%s start\n", _DBUS_FUNCTION_NAME); + _dbus_assert (transport->vtable->disconnect != NULL); - + if (transport->disconnected) return; (* transport->vtable->disconnect) (transport); transport->disconnected = TRUE; + + _dbus_verbose ("%s end\n", _DBUS_FUNCTION_NAME); } /** @@ -437,7 +443,8 @@ _dbus_transport_get_is_connected (DBusTransport *transport) * Returns #TRUE if we have been authenticated. Will return #TRUE * even if the transport is disconnected. * - * @todo needs to drop connection->mutex when calling the unix_user_function + * @todo we drop connection->mutex when calling the unix_user_function, + * which may not be safe really. * * @param transport the transport * @returns whether we're authenticated @@ -453,6 +460,9 @@ _dbus_transport_get_is_authenticated (DBusTransport *transport) if (transport->disconnected) return FALSE; + + /* paranoia ref since we call user callbacks sometimes */ + _dbus_connection_ref_unlocked (transport->connection); maybe_authenticated = (!(transport->send_credentials_pending || @@ -486,21 +496,40 @@ _dbus_transport_get_is_authenticated (DBusTransport *transport) if (transport->unix_user_function != NULL) { - /* FIXME we hold the connection lock here and should drop it */ - if (!(* transport->unix_user_function) (transport->connection, - auth_identity.uid, - transport->unix_user_data)) + dbus_bool_t allow; + DBusConnection *connection; + DBusAllowUnixUserFunction unix_user_function; + void *unix_user_data; + + /* Dropping the lock here probably isn't that safe. */ + + connection = transport->connection; + unix_user_function = transport->unix_user_function; + unix_user_data = transport->unix_user_data; + + _dbus_verbose ("unlock %s\n", _DBUS_FUNCTION_NAME); + _dbus_connection_unlock (connection); + + allow = (* unix_user_function) (connection, + auth_identity.uid, + unix_user_data); + + _dbus_verbose ("lock %s post unix user function\n", _DBUS_FUNCTION_NAME); + _dbus_connection_lock (connection); + + if (allow) + { + _dbus_verbose ("Client UID "DBUS_UID_FORMAT" authorized\n", auth_identity.uid); + } + else { _dbus_verbose ("Client UID "DBUS_UID_FORMAT " was rejected, disconnecting\n", auth_identity.uid); _dbus_transport_disconnect (transport); + _dbus_connection_unref_unlocked (connection); return FALSE; } - else - { - _dbus_verbose ("Client UID "DBUS_UID_FORMAT" authorized\n", auth_identity.uid); - } } else { @@ -515,6 +544,7 @@ _dbus_transport_get_is_authenticated (DBusTransport *transport) " but our UID is "DBUS_UID_FORMAT", disconnecting\n", auth_identity.uid, our_identity.uid); _dbus_transport_disconnect (transport); + _dbus_connection_unref_unlocked (transport->connection); return FALSE; } else @@ -527,8 +557,9 @@ _dbus_transport_get_is_authenticated (DBusTransport *transport) } transport->authenticated = maybe_authenticated; - - return transport->authenticated; + + _dbus_connection_unref_unlocked (transport->connection); + return maybe_authenticated; } } @@ -670,6 +701,8 @@ _dbus_transport_do_iteration (DBusTransport *transport, (* transport->vtable->do_iteration) (transport, flags, timeout_milliseconds); _dbus_transport_unref (transport); + + _dbus_verbose ("%s end\n", _DBUS_FUNCTION_NAME); } static dbus_bool_t @@ -31,6 +31,8 @@ Important for 1.0 - fix introspection format to handle all signatures + - make the mutex/condvar functions private + Important for 1.0 GLib Bindings === diff --git a/tools/Makefile.am b/tools/Makefile.am index b6747b0f..7cc6cadf 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -1,4 +1,4 @@ -INCLUDES=-I$(top_srcdir) $(DBUS_CLIENT_CFLAGS) $(DBUS_GLIB_CFLAGS) $(DBUS_X_CFLAGS) $(DBUS_GTK_CFLAGS) -DDBUS_LOCALEDIR=\"$(prefix)/@DATADIRNAME@/locale\" +INCLUDES=-I$(top_srcdir) $(DBUS_CLIENT_CFLAGS) $(DBUS_GLIB_CFLAGS) $(DBUS_X_CFLAGS) $(DBUS_GTK_THREADS_CFLAGS) -DDBUS_LOCALEDIR=\"$(prefix)/@DATADIRNAME@/locale\" if HAVE_GLIB GLIB_TOOLS=dbus-monitor @@ -40,7 +40,7 @@ dbus_viewer_SOURCES= \ dbus_send_LDADD= $(top_builddir)/dbus/libdbus-1.la dbus_monitor_LDADD= $(top_builddir)/glib/libdbus-glib-1.la dbus_launch_LDADD= $(DBUS_X_LIBS) -dbus_viewer_LDADD= $(DBUS_GLIB_TOOL_LIBS) $(top_builddir)/glib/libdbus-gtool.la $(DBUS_GTK_LIBS) +dbus_viewer_LDADD= $(DBUS_GLIB_TOOL_LIBS) $(top_builddir)/glib/libdbus-gtool.la $(DBUS_GTK_THREADS_LIBS) man_MANS = dbus-send.1 dbus-monitor.1 dbus-launch.1 dbus-cleanup-sockets.1 EXTRA_DIST = $(man_MANS) diff --git a/tools/dbus-tree-view.c b/tools/dbus-tree-view.c index f9342ee9..7f143ab9 100644 --- a/tools/dbus-tree-view.c +++ b/tools/dbus-tree-view.c @@ -333,6 +333,8 @@ info_set_func_text (GtkTreeViewColumn *tree_column, break; case INFO_TYPE_PROPERTY: g_string_append (str, "<i>property</i>"); + g_string_append_printf (str, " <b>%s</b>", + type_to_string (property_info_get_type ((PropertyInfo*)info))); break; case INFO_TYPE_ARG: g_string_append_printf (str, "<i>arg</i> %s", diff --git a/tools/dbus-viewer.c b/tools/dbus-viewer.c index c3903097..338b8e05 100644 --- a/tools/dbus-viewer.c +++ b/tools/dbus-viewer.c @@ -82,6 +82,54 @@ show_error_dialog (GtkWindow *transient_parent, } } +typedef struct +{ + DBusGConnection *connection; + + GtkWidget *window; + GtkWidget *treeview; + GtkWidget *name_menu; + + GtkTreeModel *names_model; + + GtkWidget *error_dialog; + +} TreeWindow; + + +static void +tree_window_set_node (TreeWindow *w, + NodeInfo *node) +{ + char **path; + const char *name; + + name = node_info_get_name (node); + if (name == NULL || + name[0] != '/') + { + g_printerr (_("Assuming root node is at path /, since no absolute path is specified")); + name = "/"; + } + + path = _dbus_gutils_split_path (name); + + dbus_tree_view_update (GTK_TREE_VIEW (w->treeview), + (const char**) path, + node); + + g_strfreev (path); +} + +typedef struct +{ + DBusGConnection *connection; + char *service_name; + GError *error; + NodeInfo *node; + TreeWindow *window; /* Not touched from child thread */ +} LoadFromServiceData; + static gboolean load_child_nodes (const char *service_name, NodeInfo *parent, @@ -179,16 +227,52 @@ load_child_nodes (const char *service_name, return TRUE; } -static NodeInfo* -load_from_service (DBusGConnection *connection, - const char *service_name, - GError **error) +static gboolean +load_from_service_complete_idle (void *data) { - DBusGProxy *root_proxy; + /* Called in main thread */ + GThread *thread = data; + LoadFromServiceData *d; + NodeInfo *node; + + d = g_thread_join (thread); + + node = d->node; + + if (d->error) + { + g_assert (d->node == NULL); + show_error_dialog (GTK_WINDOW (d->window->window), &d->window->error_dialog, + _("Unable to load \"%s\": %s\n"), + d->service_name, d->error->message); + g_error_free (d->error); + } + else + { + g_assert (d->error == NULL); + + tree_window_set_node (d->window, node); + node_info_unref (node); + } + + g_free (d->service_name); + dbus_g_connection_unref (d->connection); + g_free (d); + + return FALSE; +} + +static void* +load_from_service_thread_func (void *thread_data) +{ + DBusGProxy *root_proxy; DBusGPendingCall *call; const char *data; NodeInfo *node; GString *path; + LoadFromServiceData *lfsd; + + lfsd = thread_data; node = NULL; call = NULL; @@ -196,22 +280,22 @@ load_from_service (DBusGConnection *connection, #if 1 /* this will end up autolaunching the service when we introspect it */ - root_proxy = dbus_g_proxy_new_for_name (connection, - service_name, + root_proxy = dbus_g_proxy_new_for_name (lfsd->connection, + lfsd->service_name, "/", DBUS_INTERFACE_ORG_FREEDESKTOP_INTROSPECTABLE); g_assert (root_proxy != NULL); #else /* this will be an error if the service doesn't exist */ - root_proxy = dbus_g_proxy_new_for_name_owner (connection, - service_name, + root_proxy = dbus_g_proxy_new_for_name_owner (lfsd->connection, + lfsd->service_name, "/", DBUS_INTERFACE_ORG_FREEDESKTOP_INTROSPECTABLE, - error); + &lfsd->error); if (root_proxy == NULL) { - g_printerr ("Failed to get owner of '%s'\n", service_name); - return NULL; + g_printerr ("Failed to get owner of '%s'\n", lfsd->service_name); + return lfsd->data; } #endif @@ -219,7 +303,7 @@ load_from_service (DBusGConnection *connection, DBUS_TYPE_INVALID); data = NULL; - if (!dbus_g_proxy_end_call (root_proxy, call, error, DBUS_TYPE_STRING, &data, + if (!dbus_g_proxy_end_call (root_proxy, call, &lfsd->error, DBUS_TYPE_STRING, &data, DBUS_TYPE_INVALID)) { g_printerr ("Failed to Introspect() %s\n", @@ -227,7 +311,7 @@ load_from_service (DBusGConnection *connection, goto out; } - node = description_load_from_string (data, -1, error); + node = description_load_from_string (data, -1, &lfsd->error); /* g_print ("%s\n", data); */ @@ -239,7 +323,7 @@ load_from_service (DBusGConnection *connection, path = g_string_new ("/"); if (!load_child_nodes (dbus_g_proxy_get_bus_name (root_proxy), - node, path, error)) + node, path, &lfsd->error)) { node_info_unref (node); node = NULL; @@ -254,70 +338,40 @@ load_from_service (DBusGConnection *connection, if (path) g_string_free (path, TRUE); - - return node; -} -typedef struct -{ - DBusGConnection *connection; - - GtkWidget *window; - GtkWidget *treeview; - GtkWidget *name_menu; - - GtkTreeModel *names_model; + lfsd->node = node; + g_assert (lfsd->node || lfsd->error); + g_assert (lfsd->node == NULL || lfsd->error == NULL); - GtkWidget *error_dialog; + /* Add idle to main thread that will join us back */ + g_idle_add (load_from_service_complete_idle, g_thread_self ()); -} TreeWindow; + return lfsd; +} static void -tree_window_set_node (TreeWindow *w, - NodeInfo *node) +start_load_from_service (TreeWindow *w, + DBusGConnection *connection, + const char *service_name) { - char **path; - const char *name; + LoadFromServiceData *d; - name = node_info_get_name (node); - if (name == NULL || - name[0] != '/') - { - g_printerr (_("Assuming root node is at path /, since no absolute path is specified")); - name = "/"; - } - - path = _dbus_gutils_split_path (name); + d = g_new0 (LoadFromServiceData, 1); - dbus_tree_view_update (GTK_TREE_VIEW (w->treeview), - (const char**) path, - node); - - g_strfreev (path); + d->connection = dbus_g_connection_ref (connection); + d->service_name = g_strdup (service_name); + d->error = NULL; + d->node = NULL; + d->window = w; + + g_thread_create (load_from_service_thread_func, d, TRUE, NULL); } static void tree_window_set_service (TreeWindow *w, const char *service_name) { - GError *error; - NodeInfo *node; - - error = NULL; - node = load_from_service (w->connection, service_name, &error); - if (node == NULL) - { - g_assert (error != NULL); - show_error_dialog (GTK_WINDOW (w->window), &w->error_dialog, - _("Unable to load \"%s\": %s\n"), - service_name, error->message); - g_error_free (error); - return; - } - - tree_window_set_node (w, node); - - node_info_unref (node); + start_load_from_service (w, w->connection, service_name); } static void @@ -444,10 +498,13 @@ main (int argc, char **argv) DBusGConnection *connection; GError *error; GtkTreeModel *names_model; + + g_thread_init (NULL); + dbus_g_thread_init (); bindtextdomain (GETTEXT_PACKAGE, DBUS_LOCALEDIR); bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); - textdomain (GETTEXT_PACKAGE); + textdomain (GETTEXT_PACKAGE); gtk_init (&argc, &argv); |