X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=dbus%2Fdbus-connection.c;h=648687accb8b2e5d4253d1fed2b8c0fed36fff6b;hb=636a9a29f89326ca07d5bdbd41d874fa13910c17;hp=7f828c5fca8f387a65b73da9ca135e0814a43fd4;hpb=81656e679be3d1c51fee935d52fbc6e8748fdbef;p=platform%2Fupstream%2Fdbus.git diff --git a/dbus/dbus-connection.c b/dbus/dbus-connection.c index 7f828c5..648687a 100644 --- a/dbus/dbus-connection.c +++ b/dbus/dbus-connection.c @@ -38,6 +38,7 @@ #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" @@ -75,6 +76,14 @@ _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" : \ @@ -225,7 +234,7 @@ struct DBusPreallocatedSend DBusList *counter_link; /**< Preallocated link in the resource counter */ }; -#ifdef HAVE_DECL_MSG_NOSIGNAL +#if HAVE_DECL_MSG_NOSIGNAL static dbus_bool_t _dbus_modify_sigpipe = FALSE; #else static dbus_bool_t _dbus_modify_sigpipe = TRUE; @@ -263,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. */ @@ -655,39 +665,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 @@ -776,39 +789,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 @@ -1269,6 +1285,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"); @@ -1345,6 +1365,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) @@ -1379,13 +1400,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; } @@ -1405,22 +1421,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); } @@ -1960,7 +1962,6 @@ _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, @@ -1976,8 +1977,6 @@ _dbus_connection_send_preallocated_unlocked_no_update (DBusConnection *con connection->n_outgoing += 1; - sig = dbus_message_get_signature (message); - _dbus_verbose ("Message %p (%s %s %s %s '%s') for %s added to outgoing queue %p, %d pending to send\n", message, dbus_message_type_to_string (dbus_message_get_type (message)), @@ -1990,7 +1989,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", @@ -2109,11 +2108,23 @@ _dbus_connection_send_and_unlock (DBusConnection *connection, void _dbus_connection_close_if_only_one_ref (DBusConnection *connection) { + dbus_int32_t tmp_refcount; + CONNECTION_LOCK (connection); - - _dbus_assert (connection->refcount.value > 0); - if (connection->refcount.value == 1) + /* We increment and then decrement the refcount, because there is no + * _dbus_atomic_get (mirroring the fact that there's no InterlockedGet + * on Windows). */ + _dbus_atomic_inc (&connection->refcount); + tmp_refcount = _dbus_atomic_dec (&connection->refcount); + + /* The caller should have one ref, and this function temporarily took + * one more, which is reflected in this count even though we already + * released it (relying on the caller's ref) due to _dbus_atomic_dec + * semantics */ + _dbus_assert (tmp_refcount >= 2); + + if (tmp_refcount == 2) _dbus_connection_close_possibly_shared_and_unlock (connection); else CONNECTION_UNLOCK (connection); @@ -2365,10 +2376,10 @@ _dbus_connection_block_pending_call (DBusPendingCall *pending) * below */ timeout = _dbus_pending_call_get_timeout_unlocked (pending); + _dbus_get_current_time (&start_tv_sec, &start_tv_usec); if (timeout) { timeout_milliseconds = dbus_timeout_get_interval (timeout); - _dbus_get_current_time (&start_tv_sec, &start_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, @@ -2615,20 +2626,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; } @@ -2732,6 +2731,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); @@ -2763,28 +2764,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 @@ -3054,7 +3036,7 @@ dbus_connection_get_server_id (DBusConnection *connection) * 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. + * implementation does not know, including invalid or reserved types. * * @param connection the connection * @param type the type to check @@ -3066,7 +3048,7 @@ dbus_connection_can_send_type(DBusConnection *connection, { _dbus_return_val_if_fail (connection != NULL, FALSE); - if (!_dbus_type_is_valid(type)) + if (!dbus_type_is_valid (type)) return FALSE; if (type != DBUS_TYPE_UNIX_FD) @@ -3294,6 +3276,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); @@ -3306,6 +3289,7 @@ reply_handler_timeout (void *data) /* Unlocks, and calls out to user code */ _dbus_connection_update_dispatch_status_and_unlock (connection, status); + dbus_connection_unref (connection); return TRUE; } @@ -3332,8 +3316,9 @@ 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. If INT_MAX is passed for - * the timeout, no timeout will be set and the call will block forever. + * 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 @@ -3345,7 +3330,9 @@ reply_handler_timeout (void *data) * 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 for default or INT_MAX for no timeout + * @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. * */ @@ -3478,7 +3465,9 @@ dbus_connection_send_with_reply (DBusConnection *connection, * * @param connection the connection * @param message the message to send - * @param timeout_milliseconds timeout in milliseconds, -1 for default or INT_MAX for no timeout. + * @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. @@ -4493,6 +4482,7 @@ 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); @@ -4584,9 +4574,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; @@ -4657,7 +4644,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); @@ -4696,7 +4684,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); @@ -4819,9 +4807,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. @@ -4840,42 +4830,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 is not allowed\n"); - 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; } @@ -4904,6 +4870,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. @@ -4921,37 +4893,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 is not allowed\n"); - 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; } @@ -5569,7 +5521,7 @@ dbus_connection_remove_filter (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_object_path (DBusConnection *connection, @@ -5615,7 +5567,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, @@ -5646,7 +5599,7 @@ dbus_connection_register_object_path (DBusConnection *connection, 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); @@ -5668,7 +5621,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, @@ -5716,7 +5669,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, @@ -5747,7 +5701,7 @@ dbus_connection_register_fallback (DBusConnection *connection, 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); @@ -5911,6 +5865,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 @@ -5930,14 +5893,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) { @@ -5953,6 +5916,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 @@ -5965,13 +5937,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; } @@ -6187,6 +6159,53 @@ dbus_connection_get_outgoing_size (DBusConnection *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.