#include "dbus-memory.h"
#include "dbus-list.h"
#include "dbus-threads-internal.h"
+
#ifdef HAVE_UNIX_FD_PASSING
#include "dbus-sysdeps-unix.h"
#endif
#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_BUILD_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 */
/** 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);
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)
_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;
_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;
#endif
+ _dbus_message_trace_ref (retval, 0, 1, "copy");
return retval;
failed_copy:
DBusMessage *
dbus_message_ref (DBusMessage *message)
{
-#ifndef DBUS_DISABLE_ASSERT
dbus_int32_t old_refcount;
-#endif
_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);
-#ifdef DBUS_DISABLE_ASSERT
- _dbus_atomic_inc (&message->refcount);
-#else
old_refcount = _dbus_atomic_inc (&message->refcount);
_dbus_assert (old_refcount >= 1);
-#endif
+ _dbus_message_trace_ref (message, old_refcount, old_refcount + 1, "ref");
return message;
}
_dbus_assert (old_refcount >= 1);
+ _dbus_message_trace_ref (message, old_refcount, old_refcount - 1, "unref");
+
if (old_refcount == 1)
{
/* Calls application callbacks! */
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;
* 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
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))
{
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);
}