#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"
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;
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;
}
static void
_dbus_message_filter_unref (DBusMessageFilter *filter)
{
- _dbus_assert (filter->refcount.value > 0);
+ dbus_int32_t old_value;
- if (_dbus_atomic_dec (&filter->refcount) == 1)
+ old_value = _dbus_atomic_dec (&filter->refcount);
+ _dbus_assert (old_value > 0);
+
+ if (old_value == 1)
{
if (filter->free_user_data_function)
(* filter->free_user_data_function) (filter->user_data);
* @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;
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;
_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;
}
_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);
}
dbus_uint32_t *client_serial)
{
dbus_uint32_t serial;
- const char *sig;
preallocated->queue_link->data = message;
_dbus_list_prepend_link (&connection->outgoing_messages,
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)),
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",
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);
* 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,
{
_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
- *
- * (FIXME but for now we always use the atomic version,
- * to avoid taking the connection lock, due to
- * the mess with set_timeout_functions()/set_watch_functions()
- * calling out to the app without dropping locks)
- */
-
-#if 1
- _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;
}
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.
*/
_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
- *
- * (FIXME but for now we always use the atomic version,
- * to avoid taking the connection lock, due to
- * the mess with set_timeout_functions()/set_watch_functions()
- * calling out to the app without dropping locks)
- */
-
-#if 1
- 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
* 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
{
_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)
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);
/* Unlocks, and calls out to user code */
_dbus_connection_update_dispatch_status_and_unlock (connection, status);
+ dbus_connection_unref (connection);
return TRUE;
}
*
* 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
* 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.
*
*/
*
* @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.
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);
}
}
}
DBusPendingCall *pending;
dbus_int32_t reply_serial;
DBusDispatchStatus status;
+ dbus_bool_t found_object;
_dbus_return_val_if_fail (connection != NULL, DBUS_DISPATCH_COMPLETE);
/* 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;
HAVE_LOCK_CHECK (connection);
result = _dbus_object_tree_dispatch_and_unlock (connection->objects,
- message);
+ message,
+ &found_object);
CONNECTION_LOCK (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);
if (filter == NULL)
return FALSE;
- filter->refcount.value = 1;
-
+ _dbus_atomic_inc (&filter->refcount);
+
CONNECTION_LOCK (connection);
if (!_dbus_list_append (&connection->filter_list,
}
/**
- * 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;
CONNECTION_LOCK (connection);
retval = _dbus_object_tree_register (connection->objects,
- FALSE,
+ fallback,
(const char **) decomposed_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.
*
+ * @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.
* @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,
const DBusObjectPathVTable *vtable,
void *user_data)
{
- char **decomposed_path;
dbus_bool_t retval;
DBusError error = DBUS_ERROR_INIT;
_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);
-
- dbus_free_string_array (decomposed_path);
+ retval = _dbus_connection_register_object_path (connection, FALSE, 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);
* @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,
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);
}
/**
* @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,
const DBusObjectPathVTable *vtable,
void *user_data)
{
- char **decomposed_path;
dbus_bool_t retval;
DBusError error = DBUS_ERROR_INIT;
_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);
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.