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
This commit is contained in:
Havoc Pennington 2003-06-22 20:46:17 +00:00
parent 6843ad3176
commit 9588054183
6 changed files with 222 additions and 6 deletions

View file

@ -1,3 +1,14 @@
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)

View file

@ -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);

View file

@ -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"

View file

@ -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 */

View file

@ -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),

View file

@ -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);
}
}