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 --- mono/Message.cs | 86 +++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 81 insertions(+), 5 deletions(-) (limited to 'mono/Message.cs') 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