diff options
author | Havoc Pennington <hp@redhat.com> | 2003-06-22 20:46:17 +0000 |
---|---|---|
committer | Havoc Pennington <hp@redhat.com> | 2003-06-22 20:46:17 +0000 |
commit | 958805418359aca169cd363a4a3279f0fdab753c (patch) | |
tree | ef4d016dad313df8ad0c6f86cd715067a67c82a3 /mono | |
parent | 6843ad31769c088ca259020fd9ea8dfb3a51f68e (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
Diffstat (limited to 'mono')
-rw-r--r-- | mono/Message.cs | 86 |
1 files changed, 81 insertions, 5 deletions
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); } } |