X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=dbus%2Fdbus-connection.c;h=fad69c73cad617e53ee05bc9614cb68511ec3f52;hb=429573e69a6bd1f579a217c3dc1b8a97b57f4c09;hp=ae07adf05a6d1afc1a5a364da2963c6b52a666f1;hpb=5b4ee5fb40269afaa106b55dd4755125c2f9107a;p=platform%2Fupstream%2Fdbus.git diff --git a/dbus/dbus-connection.c b/dbus/dbus-connection.c index ae07adf..fad69c7 100644 --- a/dbus/dbus-connection.c +++ b/dbus/dbus-connection.c @@ -17,7 +17,7 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ @@ -33,14 +33,17 @@ #include "dbus-list.h" #include "dbus-hash.h" #include "dbus-message-internal.h" +#include "dbus-message-private.h" #include "dbus-threads.h" #include "dbus-protocol.h" #include "dbus-dataslot.h" #include "dbus-string.h" +#include "dbus-signature.h" #include "dbus-pending-call.h" #include "dbus-object-tree.h" #include "dbus-threads-internal.h" #include "dbus-bus.h" +#include "dbus-marshal-basic.h" #ifdef DBUS_DISABLE_CHECKS #define TOOK_LOCK_CHECK(connection) @@ -62,17 +65,25 @@ #define TRACE_LOCKS 1 #define CONNECTION_LOCK(connection) do { \ - if (TRACE_LOCKS) { _dbus_verbose (" LOCK: %s\n", _DBUS_FUNCTION_NAME); } \ + if (TRACE_LOCKS) { _dbus_verbose ("LOCK\n"); } \ _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); } \ + if (TRACE_LOCKS) { _dbus_verbose ("UNLOCK\n"); } \ RELEASING_LOCK_CHECK (connection); \ _dbus_mutex_unlock ((connection)->mutex); \ } while (0) +#define SLOTS_LOCK(connection) do { \ + _dbus_mutex_lock ((connection)->slot_mutex); \ + } while (0) + +#define SLOTS_UNLOCK(connection) do { \ + _dbus_mutex_unlock ((connection)->slot_mutex); \ + } while (0) + #define DISPATCH_STATUS_NAME(s) \ ((s) == DBUS_DISPATCH_COMPLETE ? "complete" : \ (s) == DBUS_DISPATCH_DATA_REMAINS ? "data remains" : \ @@ -223,7 +234,11 @@ struct DBusPreallocatedSend DBusList *counter_link; /**< Preallocated link in the resource counter */ }; +#if HAVE_DECL_MSG_NOSIGNAL +static dbus_bool_t _dbus_modify_sigpipe = FALSE; +#else static dbus_bool_t _dbus_modify_sigpipe = TRUE; +#endif /** * Implementation details of DBusConnection. All fields are private. @@ -257,6 +272,7 @@ struct DBusConnection DBusList *filter_list; /**< List of filters. */ + DBusMutex *slot_mutex; /**< Lock on slot_list so overall connection lock need not be taken */ DBusDataSlotList slot_list; /**< Data stored by allocated integer ID */ DBusHashTable *pending_replies; /**< Hash of message serials to #DBusPendingCall. */ @@ -320,12 +336,20 @@ static void _dbus_connection_release_dispatch (DB static DBusDispatchStatus _dbus_connection_flush_unlocked (DBusConnection *connection); static void _dbus_connection_close_possibly_shared_and_unlock (DBusConnection *connection); static dbus_bool_t _dbus_connection_get_is_connected_unlocked (DBusConnection *connection); +static dbus_bool_t _dbus_connection_peek_for_reply_unlocked (DBusConnection *connection, + dbus_uint32_t client_serial); static DBusMessageFilter * _dbus_message_filter_ref (DBusMessageFilter *filter) { - _dbus_assert (filter->refcount.value > 0); +#ifdef DBUS_DISABLE_ASSERT _dbus_atomic_inc (&filter->refcount); +#else + dbus_int32_t old_value; + + old_value = _dbus_atomic_inc (&filter->refcount); + _dbus_assert (old_value > 0); +#endif return filter; } @@ -333,9 +357,12 @@ _dbus_message_filter_ref (DBusMessageFilter *filter) static void _dbus_message_filter_unref (DBusMessageFilter *filter) { - _dbus_assert (filter->refcount.value > 0); + dbus_int32_t old_value; + + old_value = _dbus_atomic_dec (&filter->refcount); + _dbus_assert (old_value > 0); - if (_dbus_atomic_dec (&filter->refcount) == 1) + if (old_value == 1) { if (filter->free_user_data_function) (* filter->free_user_data_function) (filter->user_data); @@ -479,9 +506,9 @@ _dbus_connection_queue_received_message_link (DBusConnection *connection, _dbus_connection_wakeup_mainloop (connection); - _dbus_verbose ("Message %p (%d %s %s %s '%s' reply to %u) added to incoming queue %p, %d incoming\n", + _dbus_verbose ("Message %p (%s %s %s %s '%s' reply to %u) added to incoming queue %p, %d incoming\n", message, - dbus_message_get_type (message), + dbus_message_type_to_string (dbus_message_get_type (message)), dbus_message_get_path (message) ? dbus_message_get_path (message) : "no path", @@ -582,8 +609,8 @@ _dbus_connection_get_message_to_send (DBusConnection *connection) * @param message the message that was sent. */ void -_dbus_connection_message_sent (DBusConnection *connection, - DBusMessage *message) +_dbus_connection_message_sent_unlocked (DBusConnection *connection, + DBusMessage *message) { DBusList *link; @@ -605,9 +632,9 @@ _dbus_connection_message_sent (DBusConnection *connection, connection->n_outgoing -= 1; - _dbus_verbose ("Message %p (%d %s %s %s '%s') removed from outgoing queue %p, %d left to send\n", + _dbus_verbose ("Message %p (%s %s %s %s '%s') removed from outgoing queue %p, %d left to send\n", message, - dbus_message_get_type (message), + dbus_message_type_to_string (dbus_message_get_type (message)), dbus_message_get_path (message) ? dbus_message_get_path (message) : "no path", @@ -621,8 +648,8 @@ _dbus_connection_message_sent (DBusConnection *connection, connection, connection->n_outgoing); /* Save this link in the link cache also */ - _dbus_message_remove_size_counter (message, connection->outgoing_counter, - &link); + _dbus_message_remove_counter (message, connection->outgoing_counter, + &link); _dbus_list_prepend_link (&connection->link_cache, link); dbus_message_unref (message); @@ -647,39 +674,42 @@ protected_change_watch (DBusConnection *connection, 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 + /* The original purpose of protected_change_watch() was to hold a + * ref on the connection while dropping the connection lock, then + * calling out to the app. This was a broken hack that did not + * work, since the connection was in a hosed state (no WatchList + * field) while calling out. + * + * So for now we'll just keep the lock while calling out. This means + * apps are not allowed to call DBusConnection methods inside a + * watch function or they will deadlock. + * + * The "real fix" is to use the _and_unlock() pattern found + * elsewhere in the code, to defer calling out to the app until + * we're about to drop locks and return flow of control to the app + * anyway. + * + * See http://lists.freedesktop.org/archives/dbus/2007-July/thread.html#8144 */ - - watches = connection->watches; - if (watches) - { - connection->watches = NULL; - _dbus_connection_ref_unlocked (connection); - CONNECTION_UNLOCK (connection); + if (connection->watches) + { if (add_function) - retval = (* add_function) (watches, watch); + retval = (* add_function) (connection->watches, watch); else if (remove_function) { retval = TRUE; - (* remove_function) (watches, watch); + (* remove_function) (connection->watches, watch); } else { retval = TRUE; - (* toggle_function) (watches, watch, enabled); + (* toggle_function) (connection->watches, watch, enabled); } - - CONNECTION_LOCK (connection); - connection->watches = watches; - _dbus_connection_unref_unlocked (connection); - return retval; } else @@ -768,39 +798,42 @@ protected_change_timeout (DBusConnection *connection, 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 + /* The original purpose of protected_change_timeout() was to hold a + * ref on the connection while dropping the connection lock, then + * calling out to the app. This was a broken hack that did not + * work, since the connection was in a hosed state (no TimeoutList + * field) while calling out. + * + * So for now we'll just keep the lock while calling out. This means + * apps are not allowed to call DBusConnection methods inside a + * timeout function or they will deadlock. + * + * The "real fix" is to use the _and_unlock() pattern found + * elsewhere in the code, to defer calling out to the app until + * we're about to drop locks and return flow of control to the app + * anyway. + * + * See http://lists.freedesktop.org/archives/dbus/2007-July/thread.html#8144 */ - - timeouts = connection->timeouts; - if (timeouts) - { - connection->timeouts = NULL; - _dbus_connection_ref_unlocked (connection); - CONNECTION_UNLOCK (connection); + if (connection->timeouts) + { if (add_function) - retval = (* add_function) (timeouts, timeout); + retval = (* add_function) (connection->timeouts, timeout); else if (remove_function) { retval = TRUE; - (* remove_function) (timeouts, timeout); + (* remove_function) (connection->timeouts, timeout); } else { retval = TRUE; - (* toggle_function) (timeouts, timeout, enabled); + (* toggle_function) (connection->timeouts, timeout, enabled); } - - CONNECTION_LOCK (connection); - connection->timeouts = timeouts; - _dbus_connection_unref_unlocked (connection); - return retval; } else @@ -883,21 +916,34 @@ _dbus_connection_attach_pending_call_unlocked (DBusConnection *connection, timeout = _dbus_pending_call_get_timeout_unlocked (pending); - if (!_dbus_connection_add_timeout_unlocked (connection, timeout)) - return FALSE; - - if (!_dbus_hash_table_insert_int (connection->pending_replies, - reply_serial, - pending)) + if (timeout) { - _dbus_connection_remove_timeout_unlocked (connection, timeout); + if (!_dbus_connection_add_timeout_unlocked (connection, timeout)) + return FALSE; + + if (!_dbus_hash_table_insert_int (connection->pending_replies, + reply_serial, + pending)) + { + _dbus_connection_remove_timeout_unlocked (connection, timeout); - _dbus_pending_call_set_timeout_added_unlocked (pending, FALSE); - HAVE_LOCK_CHECK (connection); - return FALSE; + _dbus_pending_call_set_timeout_added_unlocked (pending, FALSE); + HAVE_LOCK_CHECK (connection); + return FALSE; + } + + _dbus_pending_call_set_timeout_added_unlocked (pending, TRUE); + } + else + { + if (!_dbus_hash_table_insert_int (connection->pending_replies, + reply_serial, + pending)) + { + HAVE_LOCK_CHECK (connection); + return FALSE; + } } - - _dbus_pending_call_set_timeout_added_unlocked (pending, TRUE); _dbus_pending_call_ref_unlocked (pending); @@ -1014,11 +1060,11 @@ _dbus_connection_acquire_io_path (DBusConnection *connection, /* We will only touch io_path_acquired which is protected by our mutex */ CONNECTION_UNLOCK (connection); - _dbus_verbose ("%s locking io_path_mutex\n", _DBUS_FUNCTION_NAME); + _dbus_verbose ("locking io_path_mutex\n"); _dbus_mutex_lock (connection->io_path_mutex); - _dbus_verbose ("%s start connection->io_path_acquired = %d timeout = %d\n", - _DBUS_FUNCTION_NAME, connection->io_path_acquired, timeout_milliseconds); + _dbus_verbose ("start connection->io_path_acquired = %d timeout = %d\n", + connection->io_path_acquired, timeout_milliseconds); we_acquired = FALSE; @@ -1026,8 +1072,8 @@ _dbus_connection_acquire_io_path (DBusConnection *connection, { if (timeout_milliseconds != -1) { - _dbus_verbose ("%s waiting %d for IO path to be acquirable\n", - _DBUS_FUNCTION_NAME, timeout_milliseconds); + _dbus_verbose ("waiting %d for IO path to be acquirable\n", + timeout_milliseconds); if (!_dbus_condvar_wait_timeout (connection->io_path_cond, connection->io_path_mutex, @@ -1047,7 +1093,7 @@ _dbus_connection_acquire_io_path (DBusConnection *connection, { while (connection->io_path_acquired) { - _dbus_verbose ("%s waiting for IO path to be acquirable\n", _DBUS_FUNCTION_NAME); + _dbus_verbose ("waiting for IO path to be acquirable\n"); _dbus_condvar_wait (connection->io_path_cond, connection->io_path_mutex); } @@ -1060,10 +1106,10 @@ _dbus_connection_acquire_io_path (DBusConnection *connection, connection->io_path_acquired = TRUE; } - _dbus_verbose ("%s end connection->io_path_acquired = %d we_acquired = %d\n", - _DBUS_FUNCTION_NAME, connection->io_path_acquired, we_acquired); + _dbus_verbose ("end connection->io_path_acquired = %d we_acquired = %d\n", + connection->io_path_acquired, we_acquired); - _dbus_verbose ("%s unlocking io_path_mutex\n", _DBUS_FUNCTION_NAME); + _dbus_verbose ("unlocking io_path_mutex\n"); _dbus_mutex_unlock (connection->io_path_mutex); CONNECTION_LOCK (connection); @@ -1087,18 +1133,18 @@ _dbus_connection_release_io_path (DBusConnection *connection) { HAVE_LOCK_CHECK (connection); - _dbus_verbose ("%s locking io_path_mutex\n", _DBUS_FUNCTION_NAME); + _dbus_verbose ("locking io_path_mutex\n"); _dbus_mutex_lock (connection->io_path_mutex); _dbus_assert (connection->io_path_acquired); - _dbus_verbose ("%s start connection->io_path_acquired = %d\n", - _DBUS_FUNCTION_NAME, connection->io_path_acquired); + _dbus_verbose ("start connection->io_path_acquired = %d\n", + connection->io_path_acquired); connection->io_path_acquired = FALSE; _dbus_condvar_wake_one (connection->io_path_cond); - _dbus_verbose ("%s unlocking io_path_mutex\n", _DBUS_FUNCTION_NAME); + _dbus_verbose ("unlocking io_path_mutex\n"); _dbus_mutex_unlock (connection->io_path_mutex); } @@ -1124,18 +1170,26 @@ _dbus_connection_release_io_path (DBusConnection *connection) * you specify DBUS_ITERATION_BLOCK; in that case the function * returns immediately. * + * If pending is not NULL then a check is made if the pending call + * is completed after the io path has been required. If the call + * has been completed nothing is done. This must be done since + * the _dbus_connection_acquire_io_path releases the connection + * lock for a while. + * * Called with connection lock held. * * @param connection the connection. + * @param pending the pending call that should be checked or NULL * @param flags iteration flags. * @param timeout_milliseconds maximum blocking time, or -1 for no limit. */ void _dbus_connection_do_iteration_unlocked (DBusConnection *connection, + DBusPendingCall *pending, unsigned int flags, int timeout_milliseconds) { - _dbus_verbose ("%s start\n", _DBUS_FUNCTION_NAME); + _dbus_verbose ("start\n"); HAVE_LOCK_CHECK (connection); @@ -1147,14 +1201,28 @@ _dbus_connection_do_iteration_unlocked (DBusConnection *connection, { HAVE_LOCK_CHECK (connection); - _dbus_transport_do_iteration (connection->transport, - flags, timeout_milliseconds); + if ( (pending != NULL) && _dbus_pending_call_get_completed_unlocked(pending)) + { + _dbus_verbose ("pending call completed while acquiring I/O path"); + } + else if ( (pending != NULL) && + _dbus_connection_peek_for_reply_unlocked (connection, + _dbus_pending_call_get_reply_serial_unlocked (pending))) + { + _dbus_verbose ("pending call completed while acquiring I/O path (reply found in queue)"); + } + else + { + _dbus_transport_do_iteration (connection->transport, + flags, timeout_milliseconds); + } + _dbus_connection_release_io_path (connection); } HAVE_LOCK_CHECK (connection); - _dbus_verbose ("%s end\n", _DBUS_FUNCTION_NAME); + _dbus_verbose ("end\n"); } /** @@ -1226,6 +1294,10 @@ _dbus_connection_new_for_transport (DBusTransport *transport) if (connection->io_path_cond == NULL) goto error; + _dbus_mutex_new_at_location (&connection->slot_mutex); + if (connection->slot_mutex == NULL) + goto error; + disconnect_message = dbus_message_new_signal (DBUS_PATH_LOCAL, DBUS_INTERFACE_LOCAL, "Disconnected"); @@ -1247,8 +1319,9 @@ _dbus_connection_new_for_transport (DBusTransport *transport) if (_dbus_modify_sigpipe) _dbus_disable_sigpipe (); - - connection->refcount.value = 1; + + /* initialized to 0: use atomic op to avoid mixing atomic and non-atomic */ + _dbus_atomic_inc (&connection->refcount); connection->transport = transport; connection->watches = watch_list; connection->timeouts = timeout_list; @@ -1302,6 +1375,7 @@ _dbus_connection_new_for_transport (DBusTransport *transport) _dbus_mutex_free_at_location (&connection->mutex); _dbus_mutex_free_at_location (&connection->io_path_mutex); _dbus_mutex_free_at_location (&connection->dispatch_mutex); + _dbus_mutex_free_at_location (&connection->slot_mutex); dbus_free (connection); } if (pending_replies) @@ -1336,13 +1410,8 @@ _dbus_connection_ref_unlocked (DBusConnection *connection) _dbus_assert (connection->generation == _dbus_current_generation); HAVE_LOCK_CHECK (connection); - -#ifdef DBUS_HAVE_ATOMIC_INT + _dbus_atomic_inc (&connection->refcount); -#else - _dbus_assert (connection->refcount.value > 0); - connection->refcount.value += 1; -#endif return connection; } @@ -1362,22 +1431,8 @@ _dbus_connection_unref_unlocked (DBusConnection *connection) _dbus_assert (connection != NULL); - /* The connection lock is better than the global - * lock in the atomic increment fallback - */ - -#ifdef DBUS_HAVE_ATOMIC_INT last_unref = (_dbus_atomic_dec (&connection->refcount) == 1); -#else - _dbus_assert (connection->refcount.value > 0); - connection->refcount.value -= 1; - last_unref = (connection->refcount.value == 0); -#if 0 - printf ("unref_unlocked() connection %p count = %d\n", connection, connection->refcount.value); -#endif -#endif - if (last_unref) _dbus_connection_last_unref (connection); } @@ -1419,10 +1474,17 @@ _dbus_connection_handle_watch (DBusWatch *watch, connection = data; - _dbus_verbose ("%s start\n", _DBUS_FUNCTION_NAME); + _dbus_verbose ("start\n"); CONNECTION_LOCK (connection); - _dbus_connection_acquire_io_path (connection, -1); + + if (!_dbus_connection_acquire_io_path (connection, 1)) + { + /* another thread is handling the message */ + CONNECTION_UNLOCK (connection); + return TRUE; + } + HAVE_LOCK_CHECK (connection); retval = _dbus_transport_handle_watch (connection->transport, watch, condition); @@ -1431,14 +1493,14 @@ _dbus_connection_handle_watch (DBusWatch *watch, HAVE_LOCK_CHECK (connection); - _dbus_verbose ("%s middle\n", _DBUS_FUNCTION_NAME); + _dbus_verbose ("middle\n"); 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); + _dbus_verbose ("end\n"); return retval; } @@ -1910,14 +1972,13 @@ _dbus_connection_send_preallocated_unlocked_no_update (DBusConnection *con dbus_uint32_t *client_serial) { dbus_uint32_t serial; - const char *sig; preallocated->queue_link->data = message; _dbus_list_prepend_link (&connection->outgoing_messages, preallocated->queue_link); - _dbus_message_add_size_counter_link (message, - preallocated->counter_link); + _dbus_message_add_counter_link (message, + preallocated->counter_link); dbus_free (preallocated); preallocated = NULL; @@ -1926,11 +1987,9 @@ _dbus_connection_send_preallocated_unlocked_no_update (DBusConnection *con connection->n_outgoing += 1; - sig = dbus_message_get_signature (message); - - _dbus_verbose ("Message %p (%d %s %s %s '%s') for %s added to outgoing queue %p, %d pending to send\n", + _dbus_verbose ("Message %p (%s %s %s %s '%s') for %s added to outgoing queue %p, %d pending to send\n", message, - dbus_message_get_type (message), + dbus_message_type_to_string (dbus_message_get_type (message)), dbus_message_get_path (message) ? dbus_message_get_path (message) : "no path", @@ -1940,7 +1999,7 @@ _dbus_connection_send_preallocated_unlocked_no_update (DBusConnection *con dbus_message_get_member (message) ? dbus_message_get_member (message) : "no member", - sig, + dbus_message_get_signature (message), dbus_message_get_destination (message) ? dbus_message_get_destination (message) : "null", @@ -1950,7 +2009,7 @@ _dbus_connection_send_preallocated_unlocked_no_update (DBusConnection *con if (dbus_message_get_serial (message) == 0) { serial = _dbus_connection_get_next_client_serial (connection); - _dbus_message_set_serial (message, serial); + dbus_message_set_serial (message, serial); if (client_serial) *client_serial = serial; } @@ -1963,12 +2022,13 @@ _dbus_connection_send_preallocated_unlocked_no_update (DBusConnection *con _dbus_verbose ("Message %p serial is %u\n", message, dbus_message_get_serial (message)); - _dbus_message_lock (message); + dbus_message_lock (message); /* 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_unlocked (connection, + NULL, DBUS_ITERATION_DO_WRITING, -1); @@ -1991,7 +2051,7 @@ _dbus_connection_send_preallocated_and_unlock (DBusConnection *connection, preallocated, message, client_serial); - _dbus_verbose ("%s middle\n", _DBUS_FUNCTION_NAME); + _dbus_verbose ("middle\n"); status = _dbus_connection_get_dispatch_status_unlocked (connection); /* this calls out to user code */ @@ -2058,11 +2118,15 @@ _dbus_connection_send_and_unlock (DBusConnection *connection, void _dbus_connection_close_if_only_one_ref (DBusConnection *connection) { + dbus_int32_t refcount; + CONNECTION_LOCK (connection); - - _dbus_assert (connection->refcount.value > 0); - if (connection->refcount.value == 1) + refcount = _dbus_atomic_get (&connection->refcount); + /* The caller should have at least one ref */ + _dbus_assert (refcount >= 1); + + if (refcount == 1) _dbus_connection_close_possibly_shared_and_unlock (connection); else CONNECTION_UNLOCK (connection); @@ -2137,6 +2201,32 @@ generate_local_error_message (dbus_uint32_t serial, return message; } +/* + * Peek the incoming queue to see if we got reply for a specific serial + */ +static dbus_bool_t +_dbus_connection_peek_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); + + while (link != NULL) + { + DBusMessage *reply = link->data; + + if (dbus_message_get_reply_serial (reply) == client_serial) + { + _dbus_verbose ("%s reply to %d found in queue\n", _DBUS_FUNCTION_NAME, client_serial); + return TRUE; + } + link = _dbus_list_get_next_link (&connection->incoming_messages, link); + } + + return FALSE; +} /* This is slightly strange since we can pop a message here without * the dispatch lock. @@ -2188,8 +2278,10 @@ connection_timeout_and_complete_all_pending_calls_unlocked (DBusConnection *conn _dbus_pending_call_queue_timeout_error_unlocked (pending, connection); - _dbus_connection_remove_timeout_unlocked (connection, - _dbus_pending_call_get_timeout_unlocked (pending)); + + if (_dbus_pending_call_is_timeout_added_unlocked (pending)) + _dbus_connection_remove_timeout_unlocked (connection, + _dbus_pending_call_get_timeout_unlocked (pending)); _dbus_pending_call_set_timeout_added_unlocked (pending, FALSE); _dbus_hash_iter_remove_entry (&iter); @@ -2224,7 +2316,7 @@ check_for_reply_and_update_dispatch_unlocked (DBusConnection *connection, _dbus_pending_call_get_reply_serial_unlocked (pending)); if (reply != NULL) { - _dbus_verbose ("%s checked for reply\n", _DBUS_FUNCTION_NAME); + _dbus_verbose ("checked for reply\n"); _dbus_verbose ("dbus_connection_send_with_reply_and_block(): got reply\n"); @@ -2260,12 +2352,12 @@ void _dbus_connection_block_pending_call (DBusPendingCall *pending) { long start_tv_sec, start_tv_usec; - long end_tv_sec, end_tv_usec; long tv_sec, tv_usec; DBusDispatchStatus status; DBusConnection *connection; dbus_uint32_t client_serial; - int timeout_milliseconds; + DBusTimeout *timeout; + int timeout_milliseconds, elapsed_milliseconds; _dbus_assert (pending != NULL); @@ -2285,19 +2377,23 @@ _dbus_connection_block_pending_call (DBusPendingCall *pending) * in _dbus_pending_call_new() so overflows aren't possible * below */ - timeout_milliseconds = dbus_timeout_get_interval (_dbus_pending_call_get_timeout_unlocked (pending)); - + timeout = _dbus_pending_call_get_timeout_unlocked (pending); _dbus_get_current_time (&start_tv_sec, &start_tv_usec); - end_tv_sec = start_tv_sec + timeout_milliseconds / 1000; - end_tv_usec = start_tv_usec + (timeout_milliseconds % 1000) * 1000; - end_tv_sec += end_tv_usec / _DBUS_USEC_PER_SECOND; - end_tv_usec = end_tv_usec % _DBUS_USEC_PER_SECOND; + if (timeout) + { + timeout_milliseconds = dbus_timeout_get_interval (timeout); - _dbus_verbose ("dbus_connection_send_with_reply_and_block(): will block %d milliseconds for reply serial %u from %ld sec %ld usec to %ld sec %ld usec\n", - timeout_milliseconds, - client_serial, - start_tv_sec, start_tv_usec, - end_tv_sec, end_tv_usec); + _dbus_verbose ("dbus_connection_send_with_reply_and_block(): will block %d milliseconds for reply serial %u from %ld sec %ld usec\n", + timeout_milliseconds, + client_serial, + start_tv_sec, start_tv_usec); + } + else + { + timeout_milliseconds = -1; + + _dbus_verbose ("dbus_connection_send_with_reply_and_block(): will block for reply serial %u\n", client_serial); + } /* check to see if we already got the data off the socket */ /* from another blocked pending call */ @@ -2307,13 +2403,14 @@ _dbus_connection_block_pending_call (DBusPendingCall *pending) /* Now we wait... */ /* always block at least once as we know we don't have the reply yet */ _dbus_connection_do_iteration_unlocked (connection, + pending, DBUS_ITERATION_DO_READING | DBUS_ITERATION_BLOCK, timeout_milliseconds); recheck_status: - _dbus_verbose ("%s top of recheck\n", _DBUS_FUNCTION_NAME); + _dbus_verbose ("top of recheck\n"); HAVE_LOCK_CHECK (connection); @@ -2326,7 +2423,7 @@ _dbus_connection_block_pending_call (DBusPendingCall *pending) */ if (_dbus_pending_call_get_completed_unlocked (pending)) { - _dbus_verbose ("Pending call completed by dispatch in %s\n", _DBUS_FUNCTION_NAME); + _dbus_verbose ("Pending call completed by dispatch\n"); _dbus_connection_update_dispatch_status_and_unlock (connection, status); dbus_pending_call_unref (pending); return; @@ -2339,6 +2436,8 @@ _dbus_connection_block_pending_call (DBusPendingCall *pending) } _dbus_get_current_time (&tv_sec, &tv_usec); + elapsed_milliseconds = (tv_sec - start_tv_sec) * 1000 + + (tv_usec - start_tv_usec) / 1000; if (!_dbus_connection_get_is_connected_unlocked (connection)) { @@ -2353,17 +2452,37 @@ _dbus_connection_block_pending_call (DBusPendingCall *pending) dbus_pending_call_unref (pending); return; } - 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) _dbus_verbose ("dbus_connection_send_with_reply_and_block(): disconnected\n"); - else if (tv_sec < end_tv_sec || - (tv_sec == end_tv_sec && tv_usec < end_tv_usec)) + else if (timeout == NULL) + { + if (status == DBUS_DISPATCH_NEED_MEMORY) + { + /* Try sleeping a bit, as we aren't sure we need to block for reading, + * we may already have a reply in the buffer and just can't process + * it. + */ + _dbus_verbose ("dbus_connection_send_with_reply_and_block() waiting for more memory\n"); + + _dbus_memory_pause_based_on_timeout (timeout_milliseconds - elapsed_milliseconds); + } + else + { + /* block again, we don't have the reply buffered yet. */ + _dbus_connection_do_iteration_unlocked (connection, + pending, + DBUS_ITERATION_DO_READING | + DBUS_ITERATION_BLOCK, + timeout_milliseconds - elapsed_milliseconds); + } + + goto recheck_status; + } + else if (tv_sec < start_tv_sec) + _dbus_verbose ("dbus_connection_send_with_reply_and_block(): clock set backward\n"); + else if (elapsed_milliseconds < timeout_milliseconds) { - timeout_milliseconds = (end_tv_sec - tv_sec) * 1000 + - (end_tv_usec - tv_usec) / 1000; - _dbus_verbose ("dbus_connection_send_with_reply_and_block(): %d milliseconds remain\n", timeout_milliseconds); - _dbus_assert (timeout_milliseconds >= 0); + _dbus_verbose ("dbus_connection_send_with_reply_and_block(): %d milliseconds remain\n", timeout_milliseconds - elapsed_milliseconds); if (status == DBUS_DISPATCH_NEED_MEMORY) { @@ -2373,22 +2492,23 @@ _dbus_connection_block_pending_call (DBusPendingCall *pending) */ _dbus_verbose ("dbus_connection_send_with_reply_and_block() waiting for more memory\n"); - _dbus_memory_pause_based_on_timeout (timeout_milliseconds); + _dbus_memory_pause_based_on_timeout (timeout_milliseconds - elapsed_milliseconds); } else { /* block again, we don't have the reply buffered yet. */ _dbus_connection_do_iteration_unlocked (connection, + NULL, DBUS_ITERATION_DO_READING | DBUS_ITERATION_BLOCK, - timeout_milliseconds); + timeout_milliseconds - elapsed_milliseconds); } goto recheck_status; } - _dbus_verbose ("dbus_connection_send_with_reply_and_block(): Waited %ld milliseconds and got no reply\n", - (tv_sec - start_tv_sec) * 1000 + (tv_usec - start_tv_usec) / 1000); + _dbus_verbose ("dbus_connection_send_with_reply_and_block(): Waited %d milliseconds and got no reply\n", + elapsed_milliseconds); _dbus_assert (!_dbus_pending_call_get_completed_unlocked (pending)); @@ -2508,20 +2628,8 @@ dbus_connection_ref (DBusConnection *connection) { _dbus_return_val_if_fail (connection != NULL, NULL); _dbus_return_val_if_fail (connection->generation == _dbus_current_generation, NULL); - - /* The connection lock is better than the global - * lock in the atomic increment fallback - */ - -#ifdef DBUS_HAVE_ATOMIC_INT - _dbus_atomic_inc (&connection->refcount); -#else - CONNECTION_LOCK (connection); - _dbus_assert (connection->refcount.value > 0); - connection->refcount.value += 1; - CONNECTION_UNLOCK (connection); -#endif + _dbus_atomic_inc (&connection->refcount); return connection; } @@ -2533,9 +2641,9 @@ free_outgoing_message (void *element, DBusMessage *message = element; DBusConnection *connection = data; - _dbus_message_remove_size_counter (message, - connection->outgoing_counter, - NULL); + _dbus_message_remove_counter (message, + connection->outgoing_counter, + NULL); dbus_message_unref (message); } @@ -2549,9 +2657,9 @@ _dbus_connection_last_unref (DBusConnection *connection) DBusList *link; _dbus_verbose ("Finalizing connection %p\n", connection); - - _dbus_assert (connection->refcount.value == 0); - + + _dbus_assert (_dbus_atomic_get (&connection->refcount) == 0); + /* You have to disconnect the connection before unref:ing it. Otherwise * you won't get the disconnected message. */ @@ -2625,6 +2733,8 @@ _dbus_connection_last_unref (DBusConnection *connection) _dbus_mutex_free_at_location (&connection->io_path_mutex); _dbus_mutex_free_at_location (&connection->dispatch_mutex); + _dbus_mutex_free_at_location (&connection->slot_mutex); + _dbus_mutex_free_at_location (&connection->mutex); dbus_free (connection); @@ -2656,28 +2766,9 @@ dbus_connection_unref (DBusConnection *connection) _dbus_return_if_fail (connection != NULL); _dbus_return_if_fail (connection->generation == _dbus_current_generation); - - /* The connection lock is better than the global - * lock in the atomic increment fallback - */ - -#ifdef DBUS_HAVE_ATOMIC_INT - last_unref = (_dbus_atomic_dec (&connection->refcount) == 1); -#else - CONNECTION_LOCK (connection); - - _dbus_assert (connection->refcount.value > 0); - connection->refcount.value -= 1; - last_unref = (connection->refcount.value == 0); + last_unref = (_dbus_atomic_dec (&connection->refcount) == 1); -#if 0 - printf ("unref() connection %p count = %d\n", connection, connection->refcount.value); -#endif - - CONNECTION_UNLOCK (connection); -#endif - if (last_unref) { #ifndef DBUS_DISABLE_CHECKS @@ -2927,16 +3018,60 @@ dbus_connection_get_server_id (DBusConnection *connection) { char *id; - _dbus_return_val_if_fail (connection != NULL, FALSE); - + _dbus_return_val_if_fail (connection != NULL, NULL); + CONNECTION_LOCK (connection); id = _dbus_strdup (_dbus_transport_get_server_id (connection->transport)); CONNECTION_UNLOCK (connection); - + return id; } /** + * Tests whether a certain type can be send via the connection. This + * will always return TRUE for all types, with the exception of + * DBUS_TYPE_UNIX_FD. The function will return TRUE for + * DBUS_TYPE_UNIX_FD only on systems that know Unix file descriptors + * and can send them via the chosen transport and when the remote side + * supports this. + * + * This function can be used to do runtime checking for types that + * might be unknown to the specific D-Bus client implementation + * version, i.e. it will return FALSE for all types this + * implementation does not know, including invalid or reserved types. + * + * @param connection the connection + * @param type the type to check + * @returns TRUE if the type may be send via the connection + */ +dbus_bool_t +dbus_connection_can_send_type(DBusConnection *connection, + int type) +{ + _dbus_return_val_if_fail (connection != NULL, FALSE); + + if (!dbus_type_is_valid (type)) + return FALSE; + + if (type != DBUS_TYPE_UNIX_FD) + return TRUE; + +#ifdef HAVE_UNIX_FD_PASSING + { + dbus_bool_t b; + + CONNECTION_LOCK(connection); + b = _dbus_transport_can_pass_unix_fd(connection->transport); + CONNECTION_UNLOCK(connection); + + return b; + } +#endif + + return FALSE; +} + +/** * Set whether _exit() should be called when the connection receives a * disconnect signal. The call to _exit() comes after any handlers for * the disconnect signal run; handlers can cancel the exit by calling @@ -3036,8 +3171,23 @@ dbus_connection_send_preallocated (DBusConnection *connection, _dbus_return_if_fail (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_SIGNAL || (dbus_message_get_interface (message) != NULL && dbus_message_get_member (message) != NULL)); - + CONNECTION_LOCK (connection); + +#ifdef HAVE_UNIX_FD_PASSING + + if (!_dbus_transport_can_pass_unix_fd(connection->transport) && + message->n_unix_fds > 0) + { + /* Refuse to send fds on a connection that cannot handle + them. Unfortunately we cannot return a proper error here, so + the best we can is just return. */ + CONNECTION_UNLOCK (connection); + return; + } + +#endif + _dbus_connection_send_preallocated_and_unlock (connection, preallocated, message, client_serial); @@ -3101,6 +3251,20 @@ dbus_connection_send (DBusConnection *connection, CONNECTION_LOCK (connection); +#ifdef HAVE_UNIX_FD_PASSING + + if (!_dbus_transport_can_pass_unix_fd(connection->transport) && + message->n_unix_fds > 0) + { + /* Refuse to send fds on a connection that cannot handle + them. Unfortunately we cannot return a proper error here, so + the best we can is just return. */ + CONNECTION_UNLOCK (connection); + return FALSE; + } + +#endif + return _dbus_connection_send_and_unlock (connection, message, serial); @@ -3114,6 +3278,7 @@ reply_handler_timeout (void *data) DBusPendingCall *pending = data; connection = _dbus_pending_call_get_connection_and_lock (pending); + _dbus_connection_ref_unlocked (connection); _dbus_pending_call_queue_timeout_error_unlocked (pending, connection); @@ -3121,11 +3286,12 @@ reply_handler_timeout (void *data) _dbus_pending_call_get_timeout_unlocked (pending)); _dbus_pending_call_set_timeout_added_unlocked (pending, FALSE); - _dbus_verbose ("%s middle\n", _DBUS_FUNCTION_NAME); + _dbus_verbose ("middle\n"); status = _dbus_connection_get_dispatch_status_unlocked (connection); /* Unlocks, and calls out to user code */ _dbus_connection_update_dispatch_status_and_unlock (connection, status); + dbus_connection_unref (connection); return TRUE; } @@ -3152,18 +3318,23 @@ reply_handler_timeout (void *data) * * If -1 is passed for the timeout, a sane default timeout is used. -1 * is typically the best value for the timeout for this reason, unless - * you want a very short or very long timeout. There is no way to - * avoid a timeout entirely, other than passing INT_MAX for the - * timeout to mean "very long timeout." libdbus clamps an INT_MAX - * timeout down to a few hours timeout though. + * you want a very short or very long timeout. If #DBUS_TIMEOUT_INFINITE is + * passed for the timeout, no timeout will be set and the call will block + * forever. + * + * @warning if the connection is disconnected or you try to send Unix + * file descriptors on a connection that does not support them, the + * #DBusPendingCall will be set to #NULL, so be careful with this. * - * @warning if the connection is disconnected, the #DBusPendingCall - * will be set to #NULL, so be careful with this. - * * @param connection the connection * @param message the message to send - * @param pending_return return location for a #DBusPendingCall object, or #NULL if connection is disconnected - * @param timeout_milliseconds timeout in milliseconds or -1 for default + * @param pending_return return location for a #DBusPendingCall + * object, or #NULL if connection is disconnected or when you try to + * send Unix file descriptors on a connection that does not support + * them. + * @param timeout_milliseconds timeout in milliseconds, -1 (or + * #DBUS_TIMEOUT_USE_DEFAULT) for default or #DBUS_TIMEOUT_INFINITE for no + * timeout * @returns #FALSE if no memory, #TRUE otherwise. * */ @@ -3186,6 +3357,21 @@ dbus_connection_send_with_reply (DBusConnection *connection, CONNECTION_LOCK (connection); +#ifdef HAVE_UNIX_FD_PASSING + + if (!_dbus_transport_can_pass_unix_fd(connection->transport) && + message->n_unix_fds > 0) + { + /* Refuse to send fds on a connection that cannot handle + them. Unfortunately we cannot return a proper error here, so + the best we can do is return TRUE but leave *pending_return + as NULL. */ + CONNECTION_UNLOCK (connection); + return TRUE; + } + +#endif + if (!_dbus_connection_get_is_connected_unlocked (connection)) { CONNECTION_UNLOCK (connection); @@ -3208,7 +3394,7 @@ dbus_connection_send_with_reply (DBusConnection *connection, if (serial == 0) { serial = _dbus_connection_get_next_client_serial (connection); - _dbus_message_set_serial (message, serial); + dbus_message_set_serial (message, serial); } if (!_dbus_pending_call_set_timeout_error_unlocked (pending, message, serial)) @@ -3281,7 +3467,9 @@ dbus_connection_send_with_reply (DBusConnection *connection, * * @param connection the connection * @param message the message to send - * @param timeout_milliseconds timeout in milliseconds or -1 for default + * @param timeout_milliseconds timeout in milliseconds, -1 (or + * #DBUS_TIMEOUT_USE_DEFAULT) for default or #DBUS_TIMEOUT_INFINITE for no + * timeout * @param error return location for error message * @returns the message that is the reply or #NULL with an error code if the * function fails. @@ -3294,12 +3482,26 @@ dbus_connection_send_with_reply_and_block (DBusConnection *connection, { DBusMessage *reply; DBusPendingCall *pending; - + _dbus_return_val_if_fail (connection != NULL, NULL); _dbus_return_val_if_fail (message != NULL, NULL); _dbus_return_val_if_fail (timeout_milliseconds >= 0 || timeout_milliseconds == -1, NULL); _dbus_return_val_if_error_is_set (error, NULL); - + +#ifdef HAVE_UNIX_FD_PASSING + + CONNECTION_LOCK (connection); + if (!_dbus_transport_can_pass_unix_fd(connection->transport) && + message->n_unix_fds > 0) + { + CONNECTION_UNLOCK (connection); + dbus_set_error(error, DBUS_ERROR_FAILED, "Cannot send file descriptors on this connection."); + return NULL; + } + CONNECTION_UNLOCK (connection); + +#endif + if (!dbus_connection_send_with_reply (connection, message, &pending, timeout_milliseconds)) { @@ -3340,7 +3542,7 @@ dbus_connection_send_with_reply_and_block (DBusConnection *connection, * * @param connection the connection. */ -DBusDispatchStatus +static DBusDispatchStatus _dbus_connection_flush_unlocked (DBusConnection *connection) { /* We have to specify DBUS_ITERATION_DO_READING here because @@ -3355,9 +3557,10 @@ _dbus_connection_flush_unlocked (DBusConnection *connection) while (connection->n_outgoing > 0 && _dbus_connection_get_is_connected_unlocked (connection)) { - _dbus_verbose ("doing iteration in %s\n", _DBUS_FUNCTION_NAME); + _dbus_verbose ("doing iteration in\n"); HAVE_LOCK_CHECK (connection); _dbus_connection_do_iteration_unlocked (connection, + NULL, DBUS_ITERATION_DO_READING | DBUS_ITERATION_DO_WRITING | DBUS_ITERATION_BLOCK, @@ -3365,7 +3568,7 @@ _dbus_connection_flush_unlocked (DBusConnection *connection) } HAVE_LOCK_CHECK (connection); - _dbus_verbose ("%s middle\n", _DBUS_FUNCTION_NAME); + _dbus_verbose ("middle\n"); status = _dbus_connection_get_dispatch_status_unlocked (connection); HAVE_LOCK_CHECK (connection); @@ -3397,7 +3600,7 @@ dbus_connection_flush (DBusConnection *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); + _dbus_verbose ("end\n"); } /** @@ -3427,13 +3630,13 @@ _dbus_connection_read_write_dispatch (DBusConnection *connection, if (dispatch && dstatus == DBUS_DISPATCH_DATA_REMAINS) { - _dbus_verbose ("doing dispatch in %s\n", _DBUS_FUNCTION_NAME); + _dbus_verbose ("doing dispatch\n"); dbus_connection_dispatch (connection); CONNECTION_LOCK (connection); } else if (dstatus == DBUS_DISPATCH_NEED_MEMORY) { - _dbus_verbose ("pausing for memory in %s\n", _DBUS_FUNCTION_NAME); + _dbus_verbose ("pausing for memory\n"); _dbus_memory_pause_based_on_timeout (timeout_milliseconds); CONNECTION_LOCK (connection); } @@ -3442,8 +3645,9 @@ _dbus_connection_read_write_dispatch (DBusConnection *connection, CONNECTION_LOCK (connection); if (_dbus_connection_get_is_connected_unlocked (connection)) { - _dbus_verbose ("doing iteration in %s\n", _DBUS_FUNCTION_NAME); + _dbus_verbose ("doing iteration\n"); _dbus_connection_do_iteration_unlocked (connection, + NULL, DBUS_ITERATION_DO_READING | DBUS_ITERATION_DO_WRITING | DBUS_ITERATION_BLOCK, @@ -3593,7 +3797,7 @@ dbus_connection_borrow_message (DBusConnection *connection) _dbus_return_val_if_fail (connection != NULL, NULL); - _dbus_verbose ("%s start\n", _DBUS_FUNCTION_NAME); + _dbus_verbose ("start\n"); /* this is called for the side effect that it queues * up any messages from the transport @@ -3715,9 +3919,9 @@ _dbus_connection_pop_message_link_unlocked (DBusConnection *connection) link = _dbus_list_pop_first_link (&connection->incoming_messages); connection->n_incoming -= 1; - _dbus_verbose ("Message %p (%d %s %s %s '%s') removed from incoming queue %p, %d incoming\n", + _dbus_verbose ("Message %p (%s %s %s %s '%s') removed from incoming queue %p, %d incoming\n", link->data, - dbus_message_get_type (link->data), + dbus_message_type_to_string (dbus_message_get_type (link->data)), dbus_message_get_path (link->data) ? dbus_message_get_path (link->data) : "no path", @@ -3780,9 +3984,9 @@ _dbus_connection_putback_message_link_unlocked (DBusConnection *connection, message_link); connection->n_incoming += 1; - _dbus_verbose ("Message %p (%d %s %s '%s') put back into queue %p, %d incoming\n", + _dbus_verbose ("Message %p (%s %s %s '%s') put back into queue %p, %d incoming\n", message_link->data, - dbus_message_get_type (message_link->data), + dbus_message_type_to_string (dbus_message_get_type (message_link->data)), dbus_message_get_interface (message_link->data) ? dbus_message_get_interface (message_link->data) : "no interface", @@ -3818,7 +4022,7 @@ dbus_connection_pop_message (DBusConnection *connection) DBusMessage *message; DBusDispatchStatus status; - _dbus_verbose ("%s start\n", _DBUS_FUNCTION_NAME); + _dbus_verbose ("start\n"); /* this is called for the side effect that it queues * up any messages from the transport @@ -3858,12 +4062,12 @@ _dbus_connection_acquire_dispatch (DBusConnection *connection) _dbus_connection_ref_unlocked (connection); CONNECTION_UNLOCK (connection); - _dbus_verbose ("%s locking dispatch_mutex\n", _DBUS_FUNCTION_NAME); + _dbus_verbose ("locking dispatch_mutex\n"); _dbus_mutex_lock (connection->dispatch_mutex); while (connection->dispatch_acquired) { - _dbus_verbose ("%s waiting for dispatch to be acquirable\n", _DBUS_FUNCTION_NAME); + _dbus_verbose ("waiting for dispatch to be acquirable\n"); _dbus_condvar_wait (connection->dispatch_cond, connection->dispatch_mutex); } @@ -3872,7 +4076,7 @@ _dbus_connection_acquire_dispatch (DBusConnection *connection) connection->dispatch_acquired = TRUE; - _dbus_verbose ("%s unlocking dispatch_mutex\n", _DBUS_FUNCTION_NAME); + _dbus_verbose ("unlocking dispatch_mutex\n"); _dbus_mutex_unlock (connection->dispatch_mutex); CONNECTION_LOCK (connection); @@ -3891,7 +4095,7 @@ _dbus_connection_release_dispatch (DBusConnection *connection) { HAVE_LOCK_CHECK (connection); - _dbus_verbose ("%s locking dispatch_mutex\n", _DBUS_FUNCTION_NAME); + _dbus_verbose ("locking dispatch_mutex\n"); _dbus_mutex_lock (connection->dispatch_mutex); _dbus_assert (connection->dispatch_acquired); @@ -3899,7 +4103,7 @@ _dbus_connection_release_dispatch (DBusConnection *connection) connection->dispatch_acquired = FALSE; _dbus_condvar_wake_one (connection->dispatch_cond); - _dbus_verbose ("%s unlocking dispatch_mutex\n", _DBUS_FUNCTION_NAME); + _dbus_verbose ("unlocking dispatch_mutex\n"); _dbus_mutex_unlock (connection->dispatch_mutex); } @@ -3939,7 +4143,7 @@ notify_disconnected_unlocked (DBusConnection *connection) while ((link = _dbus_list_get_last_link (&connection->outgoing_messages))) { - _dbus_connection_message_sent (connection, link->data); + _dbus_connection_message_sent_unlocked (connection, link->data); } } } @@ -3952,8 +4156,7 @@ notify_disconnected_and_dispatch_complete_unlocked (DBusConnection *connection) if (connection->disconnect_message_link != NULL) { - _dbus_verbose ("Sending disconnect message from %s\n", - _DBUS_FUNCTION_NAME); + _dbus_verbose ("Sending disconnect message\n"); /* If we have pending calls, queue their timeouts - we want the Disconnected * to be the last message, after these timeouts. @@ -4107,7 +4310,7 @@ dbus_connection_get_dispatch_status (DBusConnection *connection) _dbus_return_val_if_fail (connection != NULL, DBUS_DISPATCH_COMPLETE); - _dbus_verbose ("%s start\n", _DBUS_FUNCTION_NAME); + _dbus_verbose ("start\n"); CONNECTION_LOCK (connection); @@ -4281,10 +4484,11 @@ dbus_connection_dispatch (DBusConnection *connection) DBusPendingCall *pending; dbus_int32_t reply_serial; DBusDispatchStatus status; + dbus_bool_t found_object; _dbus_return_val_if_fail (connection != NULL, DBUS_DISPATCH_COMPLETE); - _dbus_verbose ("%s\n", _DBUS_FUNCTION_NAME); + _dbus_verbose ("\n"); CONNECTION_LOCK (connection); status = _dbus_connection_get_dispatch_status_unlocked (connection); @@ -4323,9 +4527,9 @@ dbus_connection_dispatch (DBusConnection *connection) message = message_link->data; - _dbus_verbose (" dispatching message %p (%d %s %s '%s')\n", + _dbus_verbose (" dispatching message %p (%s %s %s '%s')\n", message, - dbus_message_get_type (message), + dbus_message_type_to_string (dbus_message_get_type (message)), dbus_message_get_interface (message) ? dbus_message_get_interface (message) : "no interface", @@ -4372,9 +4576,6 @@ dbus_connection_dispatch (DBusConnection *connection) /* unlocks and calls user code */ _dbus_connection_update_dispatch_status_and_unlock (connection, DBUS_DISPATCH_NEED_MEMORY); - - if (pending) - dbus_pending_call_unref (pending); dbus_connection_unref (connection); return DBUS_DISPATCH_NEED_MEMORY; @@ -4420,7 +4621,7 @@ dbus_connection_dispatch (DBusConnection *connection) if (result == DBUS_HANDLER_RESULT_NEED_MEMORY) { - _dbus_verbose ("No memory in %s\n", _DBUS_FUNCTION_NAME); + _dbus_verbose ("No memory\n"); goto out; } else if (result == DBUS_HANDLER_RESULT_HANDLED) @@ -4432,9 +4633,9 @@ dbus_connection_dispatch (DBusConnection *connection) /* We're still protected from dispatch() reentrancy here * since we acquired the dispatcher */ - _dbus_verbose (" running object path dispatch on message %p (%d %s %s '%s')\n", + _dbus_verbose (" running object path dispatch on message %p (%s %s %s '%s')\n", message, - dbus_message_get_type (message), + dbus_message_type_to_string (dbus_message_get_type (message)), dbus_message_get_interface (message) ? dbus_message_get_interface (message) : "no interface", @@ -4445,7 +4646,8 @@ dbus_connection_dispatch (DBusConnection *connection) HAVE_LOCK_CHECK (connection); result = _dbus_object_tree_dispatch_and_unlock (connection->objects, - message); + message, + &found_object); CONNECTION_LOCK (connection); @@ -4484,7 +4686,7 @@ dbus_connection_dispatch (DBusConnection *connection) } reply = dbus_message_new_error (message, - DBUS_ERROR_UNKNOWN_METHOD, + found_object ? DBUS_ERROR_UNKNOWN_METHOD : DBUS_ERROR_UNKNOWN_OBJECT, _dbus_string_get_const_data (&str)); _dbus_string_free (&str); @@ -4513,8 +4715,8 @@ dbus_connection_dispatch (DBusConnection *connection) result = DBUS_HANDLER_RESULT_HANDLED; } - _dbus_verbose (" done dispatching %p (%d %s %s '%s') on connection %p\n", message, - dbus_message_get_type (message), + _dbus_verbose (" done dispatching %p (%s %s %s '%s') on connection %p\n", message, + dbus_message_type_to_string (dbus_message_get_type (message)), dbus_message_get_interface (message) ? dbus_message_get_interface (message) : "no interface", @@ -4527,7 +4729,7 @@ dbus_connection_dispatch (DBusConnection *connection) out: if (result == DBUS_HANDLER_RESULT_NEED_MEMORY) { - _dbus_verbose ("out of memory in %s\n", _DBUS_FUNCTION_NAME); + _dbus_verbose ("out of memory\n"); /* Put message back, and we'll start over. * Yes this means handlers must be idempotent if they @@ -4538,7 +4740,7 @@ dbus_connection_dispatch (DBusConnection *connection) } else { - _dbus_verbose (" ... done dispatching in %s\n", _DBUS_FUNCTION_NAME); + _dbus_verbose (" ... done dispatching\n"); _dbus_list_free_link (message_link); dbus_message_unref (message); /* don't want the message to count in max message limits @@ -4549,7 +4751,7 @@ dbus_connection_dispatch (DBusConnection *connection) _dbus_connection_release_dispatch (connection); HAVE_LOCK_CHECK (connection); - _dbus_verbose ("%s before final status update\n", _DBUS_FUNCTION_NAME); + _dbus_verbose ("before final status update\n"); status = _dbus_connection_get_dispatch_status_unlocked (connection); /* unlocks and calls user code */ @@ -4607,9 +4809,11 @@ dbus_connection_dispatch (DBusConnection *connection) * should be that dbus_connection_set_watch_functions() has no effect, * but the add_function and remove_function may have been called. * - * @todo We need to drop the lock when we call the - * add/remove/toggled functions which can be a side effect - * of setting the watch functions. + * @note The thread lock on DBusConnection is held while + * watch functions are invoked, so inside these functions you + * may not invoke any methods on DBusConnection or it will deadlock. + * See the comments in the code or http://lists.freedesktop.org/archives/dbus/2007-July/tread.html#8144 + * if you encounter this issue and want to attempt writing a patch. * * @param connection the connection. * @param add_function function to begin monitoring a new descriptor. @@ -4628,43 +4832,18 @@ 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_check_failed ("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); - - /* 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. - */ - watches = connection->watches; - connection->watches = NULL; - CONNECTION_UNLOCK (connection); - - retval = _dbus_watch_list_set_functions (watches, + retval = _dbus_watch_list_set_functions (connection->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; } @@ -4693,6 +4872,12 @@ dbus_connection_set_watch_functions (DBusConnection *connection, * given remove_function. The timer interval may change whenever the * timeout is added, removed, or toggled. * + * @note The thread lock on DBusConnection is held while + * timeout functions are invoked, so inside these functions you + * may not invoke any methods on DBusConnection or it will deadlock. + * See the comments in the code or http://lists.freedesktop.org/archives/dbus/2007-July/thread.html#8144 + * if you encounter this issue and want to attempt writing a patch. + * * @param connection the connection. * @param add_function function to add a timeout. * @param remove_function function to remove a timeout. @@ -4710,38 +4895,17 @@ 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_check_failed ("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 (timeouts, + retval = _dbus_timeout_list_set_functions (connection->timeouts, add_function, remove_function, toggled_function, data, free_data_function); - CONNECTION_LOCK (connection); - connection->timeouts = timeouts; - + CONNECTION_UNLOCK (connection); - /* drop our paranoid refcount */ - dbus_connection_unref (connection); return retval; } @@ -4975,10 +5139,7 @@ dbus_connection_get_unix_process_id (DBusConnection *connection, else result = _dbus_transport_get_unix_process_id (connection->transport, pid); -#ifdef DBUS_WIN - _dbus_assert (!result); -#endif - + CONNECTION_UNLOCK (connection); return result; @@ -5261,8 +5422,8 @@ dbus_connection_add_filter (DBusConnection *connection, if (filter == NULL) return FALSE; - filter->refcount.value = 1; - + _dbus_atomic_inc (&filter->refcount); + CONNECTION_LOCK (connection); if (!_dbus_list_append (&connection->filter_list, @@ -5328,6 +5489,7 @@ dbus_connection_remove_filter (DBusConnection *connection, } link = _dbus_list_get_prev_link (&connection->filter_list, link); + filter = NULL; } CONNECTION_UNLOCK (connection); @@ -5352,31 +5514,30 @@ dbus_connection_remove_filter (DBusConnection *connection, } /** - * Registers a handler for a given path in the object hierarchy. - * The given vtable handles messages sent to exactly the given path. + * Registers a handler for a given path or subsection in the object + * hierarchy. The given vtable handles messages sent to exactly the + * given path or also for paths bellow that, depending on fallback + * parameter. * * @param connection the connection + * @param fallback whether to handle messages also for "subdirectory" * @param path a '/' delimited string of path elements * @param vtable the virtual table * @param user_data data to pass to functions in the vtable * @param error address where an error can be returned * @returns #FALSE if an error (#DBUS_ERROR_NO_MEMORY or - * #DBUS_ERROR_ADDRESS_IN_USE) is reported + * #DBUS_ERROR_OBJECT_PATH_IN_USE) is reported */ -dbus_bool_t -dbus_connection_try_register_object_path (DBusConnection *connection, - const char *path, - const DBusObjectPathVTable *vtable, - void *user_data, - DBusError *error) +static dbus_bool_t +_dbus_connection_register_object_path (DBusConnection *connection, + dbus_bool_t fallback, + const char *path, + const DBusObjectPathVTable *vtable, + void *user_data, + DBusError *error) { char **decomposed_path; dbus_bool_t retval; - - _dbus_return_val_if_fail (connection != NULL, FALSE); - _dbus_return_val_if_fail (path != NULL, FALSE); - _dbus_return_val_if_fail (path[0] == '/', FALSE); - _dbus_return_val_if_fail (vtable != NULL, FALSE); if (!_dbus_decompose_path (path, strlen (path), &decomposed_path, NULL)) return FALSE; @@ -5384,7 +5545,7 @@ dbus_connection_try_register_object_path (DBusConnection *connectio CONNECTION_LOCK (connection); retval = _dbus_object_tree_register (connection->objects, - FALSE, + fallback, (const char **) decomposed_path, vtable, user_data, error); @@ -5399,6 +5560,33 @@ dbus_connection_try_register_object_path (DBusConnection *connectio * Registers a handler for a given path in the object hierarchy. * The given vtable handles messages sent to exactly the given path. * + * @param connection the connection + * @param path a '/' delimited string of path elements + * @param vtable the virtual table + * @param user_data data to pass to functions in the vtable + * @param error address where an error can be returned + * @returns #FALSE if an error (#DBUS_ERROR_NO_MEMORY or + * #DBUS_ERROR_OBJECT_PATH_IN_USE) is reported + */ +dbus_bool_t +dbus_connection_try_register_object_path (DBusConnection *connection, + const char *path, + const DBusObjectPathVTable *vtable, + void *user_data, + DBusError *error) +{ + _dbus_return_val_if_fail (connection != NULL, FALSE); + _dbus_return_val_if_fail (path != NULL, FALSE); + _dbus_return_val_if_fail (path[0] == '/', FALSE); + _dbus_return_val_if_fail (vtable != NULL, FALSE); + + return _dbus_connection_register_object_path (connection, FALSE, path, vtable, user_data, error); +} + +/** + * Registers a handler for a given path in the object hierarchy. + * The given vtable handles messages sent to exactly the given path. + * * It is a bug to call this function for object paths which already * have a handler. Use dbus_connection_try_register_object_path() if this * might be the case. @@ -5407,7 +5595,8 @@ dbus_connection_try_register_object_path (DBusConnection *connectio * @param path a '/' delimited string of path elements * @param vtable the virtual table * @param user_data data to pass to functions in the vtable - * @returns #FALSE if not enough memory + * @returns #FALSE if an error (#DBUS_ERROR_NO_MEMORY or + * #DBUS_ERROR_OBJECT_PATH_IN_USE) ocurred */ dbus_bool_t dbus_connection_register_object_path (DBusConnection *connection, @@ -5415,7 +5604,6 @@ dbus_connection_register_object_path (DBusConnection *connection, const DBusObjectPathVTable *vtable, void *user_data) { - char **decomposed_path; dbus_bool_t retval; DBusError error = DBUS_ERROR_INIT; @@ -5424,21 +5612,9 @@ dbus_connection_register_object_path (DBusConnection *connection, _dbus_return_val_if_fail (path[0] == '/', FALSE); _dbus_return_val_if_fail (vtable != NULL, FALSE); - if (!_dbus_decompose_path (path, strlen (path), &decomposed_path, NULL)) - return FALSE; - - CONNECTION_LOCK (connection); - - retval = _dbus_object_tree_register (connection->objects, - FALSE, - (const char **) decomposed_path, vtable, - user_data, &error); - - CONNECTION_UNLOCK (connection); + retval = _dbus_connection_register_object_path (connection, FALSE, path, vtable, user_data, &error); - dbus_free_string_array (decomposed_path); - - if (dbus_error_has_name (&error, DBUS_ERROR_ADDRESS_IN_USE)) + if (dbus_error_has_name (&error, DBUS_ERROR_OBJECT_PATH_IN_USE)) { _dbus_warn ("%s\n", error.message); dbus_error_free (&error); @@ -5460,7 +5636,7 @@ dbus_connection_register_object_path (DBusConnection *connection, * @param user_data data to pass to functions in the vtable * @param error address where an error can be returned * @returns #FALSE if an error (#DBUS_ERROR_NO_MEMORY or - * #DBUS_ERROR_ADDRESS_IN_USE) is reported + * #DBUS_ERROR_OBJECT_PATH_IN_USE) is reported */ dbus_bool_t dbus_connection_try_register_fallback (DBusConnection *connection, @@ -5469,29 +5645,12 @@ dbus_connection_try_register_fallback (DBusConnection *connection, void *user_data, DBusError *error) { - char **decomposed_path; - dbus_bool_t retval; - _dbus_return_val_if_fail (connection != NULL, FALSE); _dbus_return_val_if_fail (path != NULL, FALSE); _dbus_return_val_if_fail (path[0] == '/', FALSE); _dbus_return_val_if_fail (vtable != NULL, FALSE); - if (!_dbus_decompose_path (path, strlen (path), &decomposed_path, NULL)) - return FALSE; - - CONNECTION_LOCK (connection); - - retval = _dbus_object_tree_register (connection->objects, - TRUE, - (const char **) decomposed_path, vtable, - user_data, error); - - CONNECTION_UNLOCK (connection); - - dbus_free_string_array (decomposed_path); - - return retval; + return _dbus_connection_register_object_path (connection, TRUE, path, vtable, user_data, error); } /** @@ -5508,7 +5667,8 @@ dbus_connection_try_register_fallback (DBusConnection *connection, * @param path a '/' delimited string of path elements * @param vtable the virtual table * @param user_data data to pass to functions in the vtable - * @returns #FALSE if not enough memory + * @returns #FALSE if an error (#DBUS_ERROR_NO_MEMORY or + * #DBUS_ERROR_OBJECT_PATH_IN_USE) occured */ dbus_bool_t dbus_connection_register_fallback (DBusConnection *connection, @@ -5516,7 +5676,6 @@ dbus_connection_register_fallback (DBusConnection *connection, const DBusObjectPathVTable *vtable, void *user_data) { - char **decomposed_path; dbus_bool_t retval; DBusError error = DBUS_ERROR_INIT; @@ -5525,21 +5684,9 @@ dbus_connection_register_fallback (DBusConnection *connection, _dbus_return_val_if_fail (path[0] == '/', FALSE); _dbus_return_val_if_fail (vtable != NULL, FALSE); - if (!_dbus_decompose_path (path, strlen (path), &decomposed_path, NULL)) - return FALSE; - - CONNECTION_LOCK (connection); - - retval = _dbus_object_tree_register (connection->objects, - TRUE, - (const char **) decomposed_path, vtable, - user_data, &error); - - CONNECTION_UNLOCK (connection); - - dbus_free_string_array (decomposed_path); + retval = _dbus_connection_register_object_path (connection, TRUE, path, vtable, user_data, &error); - if (dbus_error_has_name (&error, DBUS_ERROR_ADDRESS_IN_USE)) + if (dbus_error_has_name (&error, DBUS_ERROR_OBJECT_PATH_IN_USE)) { _dbus_warn ("%s\n", error.message); dbus_error_free (&error); @@ -5703,6 +5850,15 @@ dbus_connection_free_data_slot (dbus_int32_t *slot_p) * the connection is finalized. The slot number * must have been allocated with dbus_connection_allocate_data_slot(). * + * @note This function does not take the + * main thread lock on DBusConnection, which allows it to be + * used from inside watch and timeout functions. (See the + * note in docs for dbus_connection_set_watch_functions().) + * A side effect of this is that you need to know there's + * a reference held on the connection while invoking + * dbus_connection_set_data(), or the connection could be + * finalized during dbus_connection_set_data(). + * * @param connection the connection * @param slot the slot number * @param data the data to store @@ -5722,14 +5878,14 @@ dbus_connection_set_data (DBusConnection *connection, _dbus_return_val_if_fail (connection != NULL, FALSE); _dbus_return_val_if_fail (slot >= 0, FALSE); - CONNECTION_LOCK (connection); + SLOTS_LOCK (connection); retval = _dbus_data_slot_list_set (&slot_allocator, &connection->slot_list, slot, data, free_data_func, &old_free_func, &old_data); - CONNECTION_UNLOCK (connection); + SLOTS_UNLOCK (connection); if (retval) { @@ -5745,6 +5901,15 @@ dbus_connection_set_data (DBusConnection *connection, * Retrieves data previously set with dbus_connection_set_data(). * The slot must still be allocated (must not have been freed). * + * @note This function does not take the + * main thread lock on DBusConnection, which allows it to be + * used from inside watch and timeout functions. (See the + * note in docs for dbus_connection_set_watch_functions().) + * A side effect of this is that you need to know there's + * a reference held on the connection while invoking + * dbus_connection_get_data(), or the connection could be + * finalized during dbus_connection_get_data(). + * * @param connection the connection * @param slot the slot to get data from * @returns the data, or #NULL if not found @@ -5757,13 +5922,13 @@ dbus_connection_get_data (DBusConnection *connection, _dbus_return_val_if_fail (connection != NULL, NULL); - CONNECTION_LOCK (connection); + SLOTS_LOCK (connection); res = _dbus_data_slot_list_get (&slot_allocator, &connection->slot_list, slot); - CONNECTION_UNLOCK (connection); + SLOTS_UNLOCK (connection); return res; } @@ -5820,6 +5985,45 @@ dbus_connection_get_max_message_size (DBusConnection *connection) } /** + * Specifies the maximum number of unix fds a message on this + * connection is allowed to receive. Messages with more unix fds will + * result in disconnecting the connection. + * + * @param connection a #DBusConnection + * @param size maximum message unix fds the connection can receive + */ +void +dbus_connection_set_max_message_unix_fds (DBusConnection *connection, + long n) +{ + _dbus_return_if_fail (connection != NULL); + + CONNECTION_LOCK (connection); + _dbus_transport_set_max_message_unix_fds (connection->transport, + n); + CONNECTION_UNLOCK (connection); +} + +/** + * Gets the value set by dbus_connection_set_max_message_unix_fds(). + * + * @param connection the connection + * @returns the max numer of unix fds of a single message + */ +long +dbus_connection_get_max_message_unix_fds (DBusConnection *connection) +{ + long res; + + _dbus_return_val_if_fail (connection != NULL, 0); + + CONNECTION_LOCK (connection); + res = _dbus_transport_get_max_message_unix_fds (connection->transport); + CONNECTION_UNLOCK (connection); + return res; +} + +/** * Sets the maximum total number of bytes that can be used for all messages * received on this connection. Messages count toward the maximum until * they are finalized. When the maximum is reached, the connection will @@ -5876,6 +6080,48 @@ dbus_connection_get_max_received_size (DBusConnection *connection) } /** + * Sets the maximum total number of unix fds that can be used for all messages + * received on this connection. Messages count toward the maximum until + * they are finalized. When the maximum is reached, the connection will + * not read more data until some messages are finalized. + * + * The semantics are analogous to those of dbus_connection_set_max_received_size(). + * + * @param connection the connection + * @param size the maximum size in bytes of all outstanding messages + */ +void +dbus_connection_set_max_received_unix_fds (DBusConnection *connection, + long n) +{ + _dbus_return_if_fail (connection != NULL); + + CONNECTION_LOCK (connection); + _dbus_transport_set_max_received_unix_fds (connection->transport, + n); + CONNECTION_UNLOCK (connection); +} + +/** + * Gets the value set by dbus_connection_set_max_received_unix_fds(). + * + * @param connection the connection + * @returns the max unix fds of all live messages + */ +long +dbus_connection_get_max_received_unix_fds (DBusConnection *connection) +{ + long res; + + _dbus_return_val_if_fail (connection != NULL, 0); + + CONNECTION_LOCK (connection); + res = _dbus_transport_get_max_received_unix_fds (connection->transport); + CONNECTION_UNLOCK (connection); + return res; +} + +/** * Gets the approximate size in bytes of all messages in the outgoing * message queue. The size is approximate in that you shouldn't use * it to decide how many bytes to read off the network or anything @@ -5891,9 +6137,76 @@ dbus_connection_get_outgoing_size (DBusConnection *connection) long res; _dbus_return_val_if_fail (connection != NULL, 0); - + + CONNECTION_LOCK (connection); + res = _dbus_counter_get_size_value (connection->outgoing_counter); + CONNECTION_UNLOCK (connection); + return res; +} + +#ifdef DBUS_ENABLE_STATS +void +_dbus_connection_get_stats (DBusConnection *connection, + dbus_uint32_t *in_messages, + dbus_uint32_t *in_bytes, + dbus_uint32_t *in_fds, + dbus_uint32_t *in_peak_bytes, + dbus_uint32_t *in_peak_fds, + dbus_uint32_t *out_messages, + dbus_uint32_t *out_bytes, + dbus_uint32_t *out_fds, + dbus_uint32_t *out_peak_bytes, + dbus_uint32_t *out_peak_fds, + dbus_uint32_t *link_cache_size) +{ + CONNECTION_LOCK (connection); + + if (in_messages != NULL) + *in_messages = connection->n_incoming; + + _dbus_transport_get_stats (connection->transport, + in_bytes, in_fds, in_peak_bytes, in_peak_fds); + + if (out_messages != NULL) + *out_messages = connection->n_outgoing; + + if (out_bytes != NULL) + *out_bytes = _dbus_counter_get_size_value (connection->outgoing_counter); + + if (out_fds != NULL) + *out_fds = _dbus_counter_get_unix_fd_value (connection->outgoing_counter); + + if (out_peak_bytes != NULL) + *out_peak_bytes = _dbus_counter_get_peak_size_value (connection->outgoing_counter); + + if (out_peak_fds != NULL) + *out_peak_fds = _dbus_counter_get_peak_unix_fd_value (connection->outgoing_counter); + + if (link_cache_size != NULL) + { + *link_cache_size = _dbus_list_get_length (&connection->link_cache) * sizeof (DBusList); + } + + CONNECTION_UNLOCK (connection); +} +#endif /* DBUS_ENABLE_STATS */ + +/** + * Gets the approximate number of uni fds of all messages in the + * outgoing message queue. + * + * @param connection the connection + * @returns the number of unix fds that have been queued up but not sent + */ +long +dbus_connection_get_outgoing_unix_fds (DBusConnection *connection) +{ + long res; + + _dbus_return_val_if_fail (connection != NULL, 0); + CONNECTION_LOCK (connection); - res = _dbus_counter_get_value (connection->outgoing_counter); + res = _dbus_counter_get_unix_fd_value (connection->outgoing_counter); CONNECTION_UNLOCK (connection); return res; }