From 958805418359aca169cd363a4a3279f0fdab753c Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Sun, 22 Jun 2003 20:46:17 +0000 Subject: 2003-06-22 Havoc Pennington * 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 --- ChangeLog | 11 +++++ dbus/dbus-internals.h | 3 +- dbus/dbus-message.c | 116 ++++++++++++++++++++++++++++++++++++++++++++++++++ dbus/dbus-message.h | 11 +++++ dbus/dbus-threads.c | 1 + mono/Message.cs | 86 ++++++++++++++++++++++++++++++++++--- 6 files changed, 222 insertions(+), 6 deletions(-) diff --git a/ChangeLog b/ChangeLog index b98f18c9..7e712582 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +2003-06-22 Havoc Pennington + + * 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 * dbus/dbus-dataslot.c (_dbus_data_slot_allocator_unref) 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 /** @@ -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 #include #include +#include #include 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); } } -- cgit