summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHavoc Pennington <hp@redhat.com>2003-06-22 20:46:17 +0000
committerHavoc Pennington <hp@redhat.com>2003-06-22 20:46:17 +0000
commit958805418359aca169cd363a4a3279f0fdab753c (patch)
treeef4d016dad313df8ad0c6f86cd715067a67c82a3
parent6843ad31769c088ca259020fd9ea8dfb3a51f68e (diff)
2003-06-22 Havoc Pennington <hp@pobox.com>
* mono/Message.cs: implement Message.Wrap() that ensures we only have a single C# wrapper per DBusMessage, assuming it works which it probably doesn't. * dbus/dbus-message.c (dbus_message_allocate_data_slot): new (dbus_message_free_data_slot): new (dbus_message_set_data): new (dbus_message_get_data): new
-rw-r--r--ChangeLog11
-rw-r--r--dbus/dbus-internals.h3
-rw-r--r--dbus/dbus-message.c116
-rw-r--r--dbus/dbus-message.h11
-rw-r--r--dbus/dbus-threads.c1
-rw-r--r--mono/Message.cs86
6 files changed, 222 insertions, 6 deletions
diff --git a/ChangeLog b/ChangeLog
index b98f18c9..7e712582 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,16 @@
2003-06-22 Havoc Pennington <hp@pobox.com>
+ * mono/Message.cs: implement Message.Wrap() that ensures we only
+ have a single C# wrapper per DBusMessage, assuming it works which
+ it probably doesn't.
+
+ * dbus/dbus-message.c (dbus_message_allocate_data_slot): new
+ (dbus_message_free_data_slot): new
+ (dbus_message_set_data): new
+ (dbus_message_get_data): new
+
+2003-06-22 Havoc Pennington <hp@pobox.com>
+
* dbus/dbus-dataslot.c (_dbus_data_slot_allocator_unref)
(_dbus_data_slot_allocator_alloc): rework these to keep a
reference count on each slot and automatically manage a global
diff --git a/dbus/dbus-internals.h b/dbus/dbus-internals.h
index 6a0ae746..d84017d7 100644
--- a/dbus/dbus-internals.h
+++ b/dbus/dbus-internals.h
@@ -229,12 +229,13 @@ extern int _dbus_current_generation;
_DBUS_DECLARE_GLOBAL_LOCK (list);
_DBUS_DECLARE_GLOBAL_LOCK (connection_slots);
_DBUS_DECLARE_GLOBAL_LOCK (server_slots);
+_DBUS_DECLARE_GLOBAL_LOCK (message_slots);
_DBUS_DECLARE_GLOBAL_LOCK (atomic);
_DBUS_DECLARE_GLOBAL_LOCK (message_handler);
_DBUS_DECLARE_GLOBAL_LOCK (bus);
_DBUS_DECLARE_GLOBAL_LOCK (shutdown_funcs);
_DBUS_DECLARE_GLOBAL_LOCK (system_users);
-#define _DBUS_N_GLOBAL_LOCKS (8)
+#define _DBUS_N_GLOBAL_LOCKS (9)
dbus_bool_t _dbus_threads_init_debug (void);
diff --git a/dbus/dbus-message.c b/dbus/dbus-message.c
index 4d80425b..85d6ce9e 100644
--- a/dbus/dbus-message.c
+++ b/dbus/dbus-message.c
@@ -29,6 +29,7 @@
#include "dbus-memory.h"
#include "dbus-list.h"
#include "dbus-message-builder.h"
+#include "dbus-dataslot.h"
#include <string.h>
/**
@@ -107,6 +108,8 @@ struct DBusMessage
dbus_uint32_t changed_stamp; /**< Incremented when iterators are invalidated. */
unsigned int locked : 1; /**< Message being sent, no modifications allowed. */
+
+ DBusDataSlotList slot_list; /**< Data stored by allocated integer ID */
};
enum {
@@ -913,6 +916,8 @@ dbus_message_new_empty_header (void)
message->byte_order = DBUS_COMPILER_BYTE_ORDER;
message->client_serial = 0;
message->reply_serial = 0;
+
+ _dbus_data_slot_list_init (&message->slot_list);
i = 0;
while (i < FIELD_LAST)
@@ -1184,6 +1189,9 @@ dbus_message_unref (DBusMessage *message)
if (old_refcount == 1)
{
+ /* This calls application callbacks! */
+ _dbus_data_slot_list_free (&message->slot_list);
+
_dbus_list_foreach (&message->size_counters,
free_size_counter, message);
_dbus_list_clear (&message->size_counters);
@@ -4609,6 +4617,114 @@ _dbus_message_loader_get_max_message_size (DBusMessageLoader *loader)
return loader->max_message_size;
}
+static DBusDataSlotAllocator slot_allocator;
+_DBUS_DEFINE_GLOBAL_LOCK (message_slots);
+
+/**
+ * Allocates an integer ID to be used for storing application-specific
+ * data on any DBusMessage. The allocated ID may then be used
+ * with dbus_message_set_data() and dbus_message_get_data().
+ * The passed-in slot must be initialized to -1, and is filled in
+ * with the slot ID. If the passed-in slot is not -1, it's assumed
+ * to be already allocated, and its refcount is incremented.
+ *
+ * The allocated slot is global, i.e. all DBusMessage objects will
+ * have a slot with the given integer ID reserved.
+ *
+ * @param slot_p address of a global variable storing the slot
+ * @returns #FALSE on failure (no memory)
+ */
+dbus_bool_t
+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);
+}
+
+/**
+ * Deallocates a global ID for message data slots.
+ * dbus_message_get_data() and dbus_message_set_data() may no
+ * longer be used with this slot. Existing data stored on existing
+ * DBusMessage objects will be freed when the message is
+ * finalized, but may not be retrieved (and may only be replaced if
+ * someone else reallocates the slot). When the refcount on the
+ * passed-in slot reaches 0, it is set to -1.
+ *
+ * @param slot_p address storing the slot to deallocate
+ */
+void
+dbus_message_free_data_slot (dbus_int32_t *slot_p)
+{
+ _dbus_return_if_fail (*slot_p >= 0);
+
+ _dbus_data_slot_allocator_free (&slot_allocator, slot_p);
+}
+
+/**
+ * Stores a pointer on a DBusMessage, along
+ * with an optional function to be used for freeing
+ * the data when the data is set again, or when
+ * the message is finalized. The slot number
+ * must have been allocated with dbus_message_allocate_data_slot().
+ *
+ * @param message the message
+ * @param slot the slot number
+ * @param data the data to store
+ * @param free_data_func finalizer function for the data
+ * @returns #TRUE if there was enough memory to store the data
+ */
+dbus_bool_t
+dbus_message_set_data (DBusMessage *message,
+ dbus_int32_t slot,
+ void *data,
+ DBusFreeFunction free_data_func)
+{
+ DBusFreeFunction old_free_func;
+ void *old_data;
+ dbus_bool_t retval;
+
+ _dbus_return_val_if_fail (message != NULL, FALSE);
+ _dbus_return_val_if_fail (slot >= 0, FALSE);
+
+ retval = _dbus_data_slot_list_set (&slot_allocator,
+ &message->slot_list,
+ slot, data, free_data_func,
+ &old_free_func, &old_data);
+
+ if (retval)
+ {
+ /* Do the actual free outside the message lock */
+ if (old_free_func)
+ (* old_free_func) (old_data);
+ }
+
+ return retval;
+}
+
+/**
+ * Retrieves data previously set with dbus_message_set_data().
+ * The slot must still be allocated (must not have been freed).
+ *
+ * @param message the message
+ * @param slot the slot to get data from
+ * @returns the data, or #NULL if not found
+ */
+void*
+dbus_message_get_data (DBusMessage *message,
+ dbus_int32_t slot)
+{
+ void *res;
+
+ _dbus_return_val_if_fail (message != NULL, NULL);
+
+ res = _dbus_data_slot_list_get (&slot_allocator,
+ &message->slot_list,
+ slot);
+
+ return res;
+}
+
/** @} */
#ifdef DBUS_BUILD_TESTS
#include "dbus-test.h"
diff --git a/dbus/dbus-message.h b/dbus/dbus-message.h
index 177f5a91..9f07565c 100644
--- a/dbus/dbus-message.h
+++ b/dbus/dbus-message.h
@@ -30,6 +30,7 @@
#include <dbus/dbus-macros.h>
#include <dbus/dbus-types.h>
#include <dbus/dbus-arch-deps.h>
+#include <dbus/dbus-memory.h>
#include <stdarg.h>
DBUS_BEGIN_DECLS;
@@ -231,6 +232,16 @@ dbus_bool_t dbus_message_iter_append_string_array (DBusMessageIter *iter,
dbus_bool_t dbus_set_error_from_message (DBusError *error,
DBusMessage *message);
+
+dbus_bool_t dbus_message_allocate_data_slot (dbus_int32_t *slot_p);
+void dbus_message_free_data_slot (dbus_int32_t *slot_p);
+dbus_bool_t dbus_message_set_data (DBusMessage *message,
+ dbus_int32_t slot,
+ void *data,
+ DBusFreeFunction free_data_func);
+void* dbus_message_get_data (DBusMessage *message,
+ dbus_int32_t slot);
+
DBUS_END_DECLS;
#endif /* DBUS_MESSAGE_H */
diff --git a/dbus/dbus-threads.c b/dbus/dbus-threads.c
index 76b2f194..5f953d82 100644
--- a/dbus/dbus-threads.c
+++ b/dbus/dbus-threads.c
@@ -224,6 +224,7 @@ init_global_locks (void)
LOCK_ADDR (list),
LOCK_ADDR (connection_slots),
LOCK_ADDR (server_slots),
+ LOCK_ADDR (message_slots),
LOCK_ADDR (atomic),
LOCK_ADDR (message_handler),
LOCK_ADDR (bus),
diff --git a/mono/Message.cs b/mono/Message.cs
index 84bd12ec..0e41c9ec 100644
--- a/mono/Message.cs
+++ b/mono/Message.cs
@@ -2,12 +2,15 @@ namespace DBus {
using System;
using System.Runtime.InteropServices;
+ using System.Diagnostics;
public class Message {
public Message (string name,
string dest_service) {
+ // the assignment bumps the refcount
raw = dbus_message_new (name, dest_service);
+ dbus_message_unref (raw);
}
public string Name {
@@ -15,23 +18,80 @@ namespace DBus {
return dbus_message_get_name (raw);
}
}
-
- IntPtr raw;
+
+ public static Message Wrap (IntPtr ptr) {
+ IntPtr gch_ptr;
+
+ gch_ptr = dbus_message_get_data (ptr, wrapper_slot);
+ if (gch_ptr != (IntPtr) 0) {
+ return (DBus.Message) ((GCHandle)gch_ptr).Target;
+ } else {
+ return new Message (ptr);
+ }
+ }
+
+ // surely there's a convention for this pattern with the property
+ // and the real member
+ IntPtr raw_;
+ IntPtr raw {
+ get {
+ return raw_;
+ }
+ set {
+ if (value == raw_)
+ return;
+
+ if (raw_ != (IntPtr) 0) {
+ IntPtr gch_ptr;
+
+ gch_ptr = dbus_message_get_data (raw_,
+ wrapper_slot);
+ Debug.Assert (gch_ptr != (IntPtr) 0);
+
+ dbus_message_set_data (raw_, wrapper_slot,
+ (IntPtr) 0, (IntPtr) 0);
+
+ ((GCHandle) gch_ptr).Free ();
+
+ dbus_message_unref (raw_);
+ }
+
+ raw_ = value;
+
+ if (raw_ != (IntPtr) 0) {
+ GCHandle gch;
+
+ dbus_message_ref (raw_);
+
+ // We store a weak reference to the C# object on the C object
+ gch = GCHandle.Alloc (this, GCHandleType.WeakTrackResurrection);
+
+ dbus_message_set_data (raw_, wrapper_slot,
+ (IntPtr) gch, (IntPtr) 0);
+ }
+ }
+ }
~Message () {
- dbus_message_unref (raw);
+ raw = (IntPtr) 0; // free the native object
}
Message (IntPtr r) {
raw = r;
- dbus_message_ref (r);
}
// static constructor runs before any methods
static Message () {
+ Debug.Assert (wrapper_slot == -1);
+ if (!dbus_message_allocate_data_slot (ref wrapper_slot))
+ throw new OutOfMemoryException ();
+
+ Debug.Assert (wrapper_slot >= 0);
}
-
+
+ // slot used to store the C# object on the C object
+ static int wrapper_slot = -1;
const string libname = "libdbus-1.so.0";
[DllImport (libname, EntryPoint="dbus_message_new")]
@@ -46,5 +106,21 @@ namespace DBus {
[DllImport (libname, EntryPoint="dbus_message_get_name")]
private extern static string dbus_message_get_name (IntPtr ptr);
+
+ [DllImport (libname, EntryPoint="dbus_message_allocate_data_slot")]
+ private extern static bool dbus_message_allocate_data_slot (ref int slot);
+
+ [DllImport (libname, EntryPoint="dbus_message_free_data_slot")]
+ private extern static void dbus_message_free_data_slot (ref int slot);
+
+ [DllImport (libname, EntryPoint="dbus_message_set_data")]
+ private extern static bool dbus_message_set_data (IntPtr ptr,
+ int slot,
+ IntPtr data,
+ IntPtr free_data_func);
+
+ [DllImport (libname, EntryPoint="dbus_message_get_data")]
+ private extern static IntPtr dbus_message_get_data (IntPtr ptr,
+ int slot);
}
}