#include <string.h>
+#define _DBUS_TYPE_IS_STRINGLIKE(type) \
+ (type == DBUS_TYPE_STRING || type == DBUS_TYPE_SIGNATURE || \
+ type == DBUS_TYPE_OBJECT_PATH)
+
static void dbus_message_finalize (DBusMessage *message);
/**
* @{
*/
+#ifdef DBUS_ENABLE_EMBEDDED_TESTS
+static dbus_bool_t
+_dbus_enable_message_cache (void)
+{
+ static int enabled = -1;
+
+ if (enabled < 0)
+ {
+ const char *s = _dbus_getenv ("DBUS_MESSAGE_CACHE");
+
+ enabled = TRUE;
+
+ if (s && *s)
+ {
+ if (*s == '0')
+ enabled = FALSE;
+ else if (*s == '1')
+ enabled = TRUE;
+ else
+ _dbus_warn ("DBUS_MESSAGE_CACHE should be 0 or 1 if set, not '%s'",
+ s);
+ }
+ }
+
+ return enabled;
+}
+#else
+ /* constant expression, should be optimized away */
+# define _dbus_enable_message_cache() (TRUE)
+#endif
+
+#ifndef _dbus_message_trace_ref
+void
+_dbus_message_trace_ref (DBusMessage *message,
+ int old_refcount,
+ int new_refcount,
+ const char *why)
+{
+ static int enabled = -1;
+
+ _dbus_trace_ref ("DBusMessage", message, old_refcount, new_refcount, why,
+ "DBUS_MESSAGE_TRACE", &enabled);
+}
+#endif
+
/* Not thread locked, but strictly const/read-only so should be OK
*/
/** An static string representing an empty signature */
{
const DBusString *type_str;
int type_pos;
-
- if (message->byte_order == DBUS_COMPILER_BYTE_ORDER)
+ char byte_order;
+
+ byte_order = _dbus_header_get_byte_order (&message->header);
+
+ if (byte_order == DBUS_COMPILER_BYTE_ORDER)
return;
_dbus_verbose ("Swapping message into compiler byte order\n");
get_const_signature (&message->header, &type_str, &type_pos);
_dbus_marshal_byteswap (type_str, type_pos,
- message->byte_order,
+ byte_order,
DBUS_COMPILER_BYTE_ORDER,
&message->body, 0);
- message->byte_order = DBUS_COMPILER_BYTE_ORDER;
-
_dbus_header_byteswap (&message->header, DBUS_COMPILER_BYTE_ORDER);
+ _dbus_assert (_dbus_header_get_byte_order (&message->header) ==
+ DBUS_COMPILER_BYTE_ORDER);
}
/** byte-swap the message if it doesn't match our byte order.
* Otherwise should not be called since it would do needless
* work.
*/
-#define ensure_byte_order(message) \
- if (message->byte_order != DBUS_COMPILER_BYTE_ORDER) \
- _dbus_message_byteswap (message)
+#define ensure_byte_order(message) _dbus_message_byteswap (message)
/**
* Gets the data to be sent over the network for this message.
* itself not incremented. Ownership of link and counter refcount is
* passed to the message.
*
+ * This function may be called with locks held. As a result, the counter's
+ * notify function is not called; the caller is expected to either call
+ * _dbus_counter_notify() on the counter when they are no longer holding
+ * locks, or take the same action that would be taken by the notify function.
+ *
* @param message the message
* @param link link with counter as data
*/
* of this message, and decremented by the size/unix fds of this
* message when this message if finalized.
*
+ * This function may be called with locks held. As a result, the counter's
+ * notify function is not called; the caller is expected to either call
+ * _dbus_counter_notify() on the counter when they are no longer holding
+ * locks, or take the same action that would be taken by the notify function.
+ *
* @param message the message
* @param counter the counter
* @returns #FALSE if no memory
* decrements the counter by the size/unix fds of this message.
*
* @param message the message
- * @param link_return return the link used
* @param counter the counter
*/
void
_dbus_message_remove_counter (DBusMessage *message,
- DBusCounter *counter,
- DBusList **link_return)
+ DBusCounter *counter)
{
DBusList *link;
counter);
_dbus_assert (link != NULL);
- _dbus_list_unlink (&message->counters,
- link);
- if (link_return)
- *link_return = link;
- else
- _dbus_list_free_link (link);
+ _dbus_list_remove_link (&message->counters, link);
_dbus_counter_adjust_size (counter, - message->size_counter_delta);
_dbus_counter_adjust_unix_fd (counter, - message->unix_fd_counter_delta);
#endif
+ _dbus_counter_notify (counter);
_dbus_counter_unref (counter);
}
/** Avoid caching too many messages */
#define MAX_MESSAGE_CACHE_SIZE 5
-_DBUS_DEFINE_GLOBAL_LOCK (message_cache);
+/* Protected by _DBUS_LOCK (message_cache) */
static DBusMessage *message_cache[MAX_MESSAGE_CACHE_SIZE];
static int message_cache_count = 0;
static dbus_bool_t message_cache_shutdown_registered = FALSE;
{
int i;
- _DBUS_LOCK (message_cache);
+ if (!_DBUS_LOCK (message_cache))
+ _dbus_assert_not_reached ("we would have initialized global locks "
+ "before registering a shutdown function");
i = 0;
while (i < MAX_MESSAGE_CACHE_SIZE)
message = NULL;
- _DBUS_LOCK (message_cache);
+ if (!_DBUS_LOCK (message_cache))
+ {
+ /* we'd have initialized global locks before caching anything,
+ * so there can't be anything in the cache */
+ return NULL;
+ }
_dbus_assert (message_cache_count >= 0);
_dbus_assert (i < MAX_MESSAGE_CACHE_SIZE);
_dbus_assert (message != NULL);
- _dbus_assert (message->refcount.value == 0);
+ _dbus_assert (_dbus_atomic_get (&message->refcount) == 0);
+
_dbus_assert (message->counters == NULL);
_DBUS_UNLOCK (message_cache);
_dbus_counter_adjust_unix_fd (counter, - message->unix_fd_counter_delta);
#endif
+ _dbus_counter_notify (counter);
_dbus_counter_unref (counter);
}
{
dbus_bool_t was_cached;
int i;
-
- _dbus_assert (message->refcount.value == 0);
+
+ _dbus_assert (_dbus_atomic_get (&message->refcount) == 0);
/* This calls application code and has to be done first thing
* without holding the lock
was_cached = FALSE;
- _DBUS_LOCK (message_cache);
+ if (!_DBUS_LOCK (message_cache))
+ {
+ /* The only way to get a non-null message goes through
+ * dbus_message_get_cached() which takes the lock. */
+ _dbus_assert_not_reached ("we would have initialized global locks "
+ "the first time we constructed a message");
+ }
if (!message_cache_shutdown_registered)
{
_dbus_assert (message_cache_count >= 0);
+ if (!_dbus_enable_message_cache ())
+ goto out;
+
if ((_dbus_string_get_length (&message->header.data) +
_dbus_string_get_length (&message->body)) >
MAX_MESSAGE_SIZE_TO_CACHE)
#endif
out:
- _dbus_assert (message->refcount.value == 0);
-
+ _dbus_assert (_dbus_atomic_get (&message->refcount) == 0);
+
_DBUS_UNLOCK (message_cache);
if (!was_cached)
dbus_message_finalize (message);
}
-#ifndef DBUS_DISABLE_CHECKS
+#if defined(DBUS_ENABLE_CHECKS) || defined(DBUS_ENABLE_ASSERT)
static dbus_bool_t
_dbus_message_iter_check (DBusMessageRealIter *iter)
{
+ char byte_order;
+
if (iter == NULL)
{
_dbus_warn_check_failed ("dbus message iterator is NULL\n");
return FALSE;
}
+ byte_order = _dbus_header_get_byte_order (&iter->message->header);
+
if (iter->iter_type == DBUS_MESSAGE_ITER_TYPE_READER)
{
- if (iter->u.reader.byte_order != iter->message->byte_order)
+ if (iter->u.reader.byte_order != byte_order)
{
_dbus_warn_check_failed ("dbus message changed byte order since iterator was created\n");
return FALSE;
}
else if (iter->iter_type == DBUS_MESSAGE_ITER_TYPE_WRITER)
{
- if (iter->u.writer.byte_order != iter->message->byte_order)
+ if (iter->u.writer.byte_order != byte_order)
{
_dbus_warn_check_failed ("dbus message changed byte order since append iterator was created\n");
return FALSE;
return TRUE;
}
-#endif /* DBUS_DISABLE_CHECKS */
+#endif /* DBUS_ENABLE_CHECKS || DBUS_ENABLE_ASSERT */
/**
* Implementation of the varargs arg-getting functions.
_dbus_type_reader_read_fixed_multi (&array,
(void *) ptr, n_elements_p);
}
- else if (spec_element_type == DBUS_TYPE_STRING ||
- spec_element_type == DBUS_TYPE_SIGNATURE ||
- spec_element_type == DBUS_TYPE_OBJECT_PATH)
+ else if (_DBUS_TYPE_IS_STRINGLIKE (spec_element_type))
{
char ***str_array_p;
int n_elements;
static void
dbus_message_finalize (DBusMessage *message)
{
- _dbus_assert (message->refcount.value == 0);
+ _dbus_assert (_dbus_atomic_get (&message->refcount) == 0);
/* This calls application callbacks! */
_dbus_data_slot_list_free (&message->slot_list);
dbus_free(message->unix_fds);
#endif
- _dbus_assert (message->refcount.value == 0);
-
+ _dbus_assert (_dbus_atomic_get (&message->refcount) == 0);
+
dbus_free (message);
}
else
{
from_cache = FALSE;
- message = dbus_new (DBusMessage, 1);
+ message = dbus_new0 (DBusMessage, 1);
if (message == NULL)
return NULL;
#ifndef DBUS_DISABLE_CHECKS
message->n_unix_fds_allocated = 0;
#endif
}
-
- message->refcount.value = 1;
- message->byte_order = DBUS_COMPILER_BYTE_ORDER;
+
+ _dbus_atomic_inc (&message->refcount);
+
+ _dbus_message_trace_ref (message, 0, 1, "new_empty_header");
+
message->locked = FALSE;
#ifndef DBUS_DISABLE_CHECKS
message->in_cache = FALSE;
if (from_cache)
{
- _dbus_header_reinit (&message->header, message->byte_order);
+ _dbus_header_reinit (&message->header);
_dbus_string_set_length (&message->body, 0);
}
else
{
- if (!_dbus_header_init (&message->header, message->byte_order))
+ if (!_dbus_header_init (&message->header))
{
dbus_free (message);
return NULL;
return NULL;
if (!_dbus_header_create (&message->header,
+ DBUS_COMPILER_BYTE_ORDER,
message_type,
NULL, NULL, NULL, NULL, NULL))
{
return NULL;
if (!_dbus_header_create (&message->header,
+ DBUS_COMPILER_BYTE_ORDER,
DBUS_MESSAGE_TYPE_METHOD_CALL,
destination, path, interface, method, NULL))
{
return NULL;
if (!_dbus_header_create (&message->header,
+ DBUS_COMPILER_BYTE_ORDER,
DBUS_MESSAGE_TYPE_METHOD_RETURN,
sender, NULL, NULL, NULL, NULL))
{
return NULL;
if (!_dbus_header_create (&message->header,
+ DBUS_COMPILER_BYTE_ORDER,
DBUS_MESSAGE_TYPE_SIGNAL,
NULL, path, interface, name, NULL))
{
return NULL;
if (!_dbus_header_create (&message->header,
+ DBUS_COMPILER_BYTE_ORDER,
DBUS_MESSAGE_TYPE_ERROR,
sender, NULL, NULL, NULL, error_name))
{
if (retval == NULL)
return NULL;
- retval->refcount.value = 1;
- retval->byte_order = message->byte_order;
+ _dbus_atomic_inc (&retval->refcount);
+
retval->locked = FALSE;
#ifndef DBUS_DISABLE_CHECKS
retval->generation = message->generation;
#endif
+ _dbus_message_trace_ref (retval, 0, 1, "copy");
return retval;
failed_copy:
_dbus_return_val_if_fail (message != NULL, NULL);
_dbus_return_val_if_fail (message->generation == _dbus_current_generation, NULL);
_dbus_return_val_if_fail (!message->in_cache, NULL);
-
+
old_refcount = _dbus_atomic_inc (&message->refcount);
_dbus_assert (old_refcount >= 1);
+ _dbus_message_trace_ref (message, old_refcount, old_refcount + 1, "ref");
return message;
}
old_refcount = _dbus_atomic_dec (&message->refcount);
- _dbus_assert (old_refcount >= 0);
+ _dbus_assert (old_refcount >= 1);
+
+ _dbus_message_trace_ref (message, old_refcount, old_refcount - 1, "unref");
if (old_refcount == 1)
{
goto failed;
}
}
- else if (element_type == DBUS_TYPE_STRING ||
- element_type == DBUS_TYPE_SIGNATURE ||
- element_type == DBUS_TYPE_OBJECT_PATH)
+ else if (_DBUS_TYPE_IS_STRINGLIKE (element_type))
{
const char ***value_p;
const char **value;
DBUS_MESSAGE_ITER_TYPE_READER);
_dbus_type_reader_init (&real->u.reader,
- message->byte_order,
+ _dbus_header_get_byte_order (&message->header),
type_str, type_pos,
&message->body,
0);
* descriptors), you can get all the array elements at once with
* dbus_message_iter_get_fixed_array(). Otherwise, you have to iterate
* over the container's contents one value at a time.
- *
- * All basic-typed values are guaranteed to fit in 8 bytes. So you can
- * write code like this:
+ *
+ * All basic-typed values are guaranteed to fit in a #DBusBasicValue,
+ * so in versions of libdbus that have that type, you can write code like this:
*
* @code
- * dbus_uint64_t value;
+ * DBusBasicValue value;
* int type;
* dbus_message_iter_get_basic (&read_iter, &value);
* type = dbus_message_iter_get_arg_type (&read_iter);
* dbus_message_iter_append_basic (&write_iter, type, &value);
* @endcode
*
- * On some really obscure platforms dbus_uint64_t might not exist, if
- * you need to worry about this you will know. dbus_uint64_t is just
- * one example of a type that's large enough to hold any possible
- * value, you could use a struct or char[8] instead if you like.
+ * (All D-Bus basic types are either numeric and 8 bytes or smaller, or
+ * behave like a string; so in older versions of libdbus, DBusBasicValue
+ * can be replaced with union { char *string; unsigned char bytes[8]; },
+ * for instance.)
*
* @param iter the iterator
* @param value location to store the value
int *n_elements)
{
DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
+#ifndef DBUS_DISABLE_CHECKS
int subtype = _dbus_type_reader_get_current_type(&real->u.reader);
_dbus_return_if_fail (_dbus_message_iter_check (real));
_dbus_return_if_fail (value != NULL);
_dbus_return_if_fail ((subtype == DBUS_TYPE_INVALID) ||
(dbus_type_is_fixed (subtype) && subtype != DBUS_TYPE_UNIX_FD));
+#endif
_dbus_type_reader_read_fixed_multi (&real->u.reader,
value, n_elements);
* due to OOM.
*/
_dbus_type_writer_init_types_delayed (&real->u.writer,
- message->byte_order,
+ _dbus_header_get_byte_order (&message->header),
&message->body,
_dbus_string_get_length (&message->body));
}
DBusMessageIter *sub)
{
DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
+#ifndef DBUS_DISABLE_CHECKS
DBusMessageRealIter *real_sub = (DBusMessageRealIter *)sub;
_dbus_return_if_fail (_dbus_message_iter_append_check (real));
_dbus_return_if_fail (real->iter_type == DBUS_MESSAGE_ITER_TYPE_WRITER);
_dbus_return_if_fail (_dbus_message_iter_append_check (real_sub));
_dbus_return_if_fail (real_sub->iter_type == DBUS_MESSAGE_ITER_TYPE_WRITER);
+#endif
_dbus_message_iter_abandon_signature (real);
}
SCM_RIGHTS works we need to preallocate an fd array of the maximum
number of unix fds we want to receive in advance. A
try-and-reallocate loop is not possible. */
- loader->max_message_unix_fds = 1024;
+ loader->max_message_unix_fds = DBUS_DEFAULT_MESSAGE_UNIX_FDS;
if (!_dbus_string_init (&loader->data))
{
_dbus_assert (validity == DBUS_VALID);
- message->byte_order = byte_order;
-
/* 2. VALIDATE BODY */
if (mode != DBUS_VALIDATION_MODE_WE_TRUST_THIS_DATA_ABSOLUTELY)
{
return loader->max_message_unix_fds;
}
-static DBusDataSlotAllocator slot_allocator;
-_DBUS_DEFINE_GLOBAL_LOCK (message_slots);
+static DBusDataSlotAllocator slot_allocator =
+ _DBUS_DATA_SLOT_ALLOCATOR_INIT (_DBUS_LOCK_NAME (message_slots));
/**
* Allocates an integer ID to be used for storing application-specific
dbus_message_allocate_data_slot (dbus_int32_t *slot_p)
{
return _dbus_data_slot_allocator_alloc (&slot_allocator,
- &_DBUS_LOCK_NAME (message_slots),
slot_p);
}
if (validity == DBUS_VALID)
{
_dbus_assert (have_message || (header_len + body_len) > len);
+ (void) have_message; /* unused unless asserting */
return header_len + body_len;
}
else