summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHavoc Pennington <hp@redhat.com>2003-07-09 03:41:00 +0000
committerHavoc Pennington <hp@redhat.com>2003-07-09 03:41:00 +0000
commit824d4a5edfe1fa7222ab5cb49928bf78a675b563 (patch)
tree67e3e45df77fc7fa4277507895cf650ce7f61917
parentd8abf955f5bff3e83cabd267883039f7a42c98c3 (diff)
downloaddbus-824d4a5edfe1fa7222ab5cb49928bf78a675b563.tar.gz
2003-07-08 Havoc Pennington <hp@pobox.com>
* dbus/dbus-object.c: implement some of this * dbus/dbus-object-registry.c (_dbus_object_registry_add_and_unlock): fill in the object_id out param (_dbus_object_registry_new): handle OOM
-rw-r--r--ChangeLog9
-rw-r--r--dbus/dbus-connection.c45
-rw-r--r--dbus/dbus-connection.h13
-rw-r--r--dbus/dbus-internals.h3
-rw-r--r--dbus/dbus-message-handler.c2
-rw-r--r--dbus/dbus-message.h1
-rw-r--r--dbus/dbus-object-registry.c12
-rw-r--r--dbus/dbus-object.c324
-rw-r--r--dbus/dbus-object.h25
-rw-r--r--dbus/dbus-test.c6
-rw-r--r--dbus/dbus-test.h1
-rw-r--r--dbus/dbus-threads.c1
12 files changed, 415 insertions, 27 deletions
diff --git a/ChangeLog b/ChangeLog
index 9ed9055c..6cf65315 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,14 @@
2003-07-08 Havoc Pennington <hp@pobox.com>
+ * dbus/dbus-object.c: implement some of this
+
+ * dbus/dbus-object-registry.c
+ (_dbus_object_registry_add_and_unlock): fill in the object_id out
+ param
+ (_dbus_object_registry_new): handle OOM
+
+2003-07-08 Havoc Pennington <hp@pobox.com>
+
* dbus/dbus-object.h: sketch out an API for registering objects
with a connection, that allows us to use as little as 24 bytes
per object and lets application code represent an object in
diff --git a/dbus/dbus-connection.c b/dbus/dbus-connection.c
index 237c195b..ed29edc9 100644
--- a/dbus/dbus-connection.c
+++ b/dbus/dbus-connection.c
@@ -2942,6 +2942,51 @@ dbus_connection_unregister_handler (DBusConnection *connection,
CONNECTION_UNLOCK (connection);
}
+/**
+ * Registers an object with the connection. This object is assigned an
+ * object ID, and will be visible under this ID and with the provided
+ * interfaces to the peer application on the other end of the
+ * connection. The object instance should be passed in as object_impl;
+ * the instance can be any datatype, as long as it fits in a void*.
+ *
+ * As a side effect of calling this function, the "registered"
+ * callback in the #DBusObjectVTable will be invoked.
+ *
+ * @param connection the connection to register the instance with
+ * @param interfaces #NULL-terminated array of interface names the instance supports
+ * @param vtable virtual table of functions for manipulating the instance
+ * @param object_impl object instance
+ * @param object_id if non-#NULL, object ID to initialize with the new object's ID
+ * @returns #FALSE if not enough memory to register the object instance
+ */
+dbus_bool_t
+dbus_connection_register_object (DBusConnection *connection,
+ const char **interfaces,
+ const DBusObjectVTable *vtable,
+ void *object_impl,
+ DBusObjectID *object_id)
+{
+
+ return FALSE;
+}
+
+/**
+ * Reverses the effects of dbus_connection_register_object(),
+ * and invokes the "unregistered" callback in the #DBusObjectVTable
+ * for the given object. The passed-in object ID must be a valid,
+ * registered object ID or the results are undefined.
+ *
+ * @param connection the connection to unregister the object ID from
+ * @param object_id the object ID to unregister
+ */
+void
+dbus_connection_unregister_object (DBusConnection *connection,
+ const DBusObjectID *object_id)
+{
+
+
+}
+
static DBusDataSlotAllocator slot_allocator;
_DBUS_DEFINE_GLOBAL_LOCK (connection_slots);
diff --git a/dbus/dbus-connection.h b/dbus/dbus-connection.h
index ce57c98d..6c0da920 100644
--- a/dbus/dbus-connection.h
+++ b/dbus/dbus-connection.h
@@ -28,12 +28,11 @@
#define DBUS_CONNECTION_H
#include <dbus/dbus-errors.h>
-#include <dbus/dbus-message.h>
#include <dbus/dbus-memory.h>
+#include <dbus/dbus-object.h>
DBUS_BEGIN_DECLS;
-typedef struct DBusConnection DBusConnection;
typedef struct DBusWatch DBusWatch;
typedef struct DBusTimeout DBusTimeout;
typedef struct DBusMessageHandler DBusMessageHandler;
@@ -172,7 +171,17 @@ void dbus_connection_unregister_handler (DBusConnection *connection,
const char **messages_to_handle,
int n_messages);
+/* Objects */
+dbus_bool_t dbus_connection_register_object (DBusConnection *connection,
+ const char **interfaces,
+ const DBusObjectVTable *vtable,
+ void *object_impl,
+ DBusObjectID *object_id);
+void dbus_connection_unregister_object (DBusConnection *connection,
+ const DBusObjectID *object_id);
+
+/* Other */
dbus_bool_t dbus_connection_allocate_data_slot (dbus_int32_t *slot_p);
void dbus_connection_free_data_slot (dbus_int32_t *slot_p);
dbus_bool_t dbus_connection_set_data (DBusConnection *connection,
diff --git a/dbus/dbus-internals.h b/dbus/dbus-internals.h
index d84017d7..7acda71a 100644
--- a/dbus/dbus-internals.h
+++ b/dbus/dbus-internals.h
@@ -232,10 +232,11 @@ _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 (callback_object);
_DBUS_DECLARE_GLOBAL_LOCK (bus);
_DBUS_DECLARE_GLOBAL_LOCK (shutdown_funcs);
_DBUS_DECLARE_GLOBAL_LOCK (system_users);
-#define _DBUS_N_GLOBAL_LOCKS (9)
+#define _DBUS_N_GLOBAL_LOCKS (10)
dbus_bool_t _dbus_threads_init_debug (void);
diff --git a/dbus/dbus-message-handler.c b/dbus/dbus-message-handler.c
index f38e5100..8bb4dd18 100644
--- a/dbus/dbus-message-handler.c
+++ b/dbus/dbus-message-handler.c
@@ -325,7 +325,7 @@ free_test_data (void *data)
}
/**
- * @ingroup DBusMessageInternals
+ * @ingroup DBusMessageHandlerInternals
* Unit test for DBusMessageHandler.
*
* @returns #TRUE on success.
diff --git a/dbus/dbus-message.h b/dbus/dbus-message.h
index 9f07565c..bd52bd1a 100644
--- a/dbus/dbus-message.h
+++ b/dbus/dbus-message.h
@@ -31,6 +31,7 @@
#include <dbus/dbus-types.h>
#include <dbus/dbus-arch-deps.h>
#include <dbus/dbus-memory.h>
+#include <dbus/dbus-errors.h>
#include <stdarg.h>
DBUS_BEGIN_DECLS;
diff --git a/dbus/dbus-object-registry.c b/dbus/dbus-object-registry.c
index 9f7ca3ff..eba2d8fb 100644
--- a/dbus/dbus-object-registry.c
+++ b/dbus/dbus-object-registry.c
@@ -66,7 +66,9 @@ _dbus_object_registry_new (DBusConnection *connection)
DBusObjectRegistry *registry;
registry = dbus_new0 (DBusObjectRegistry, 1);
-
+ if (registry == NULL)
+ return NULL;
+
registry->refcount = 1;
registry->connection = connection;
@@ -230,7 +232,9 @@ _dbus_object_registry_add_and_unlock (DBusObjectRegistry *registry,
registry->entries[i].object_impl = object_impl;
info_from_entry (registry, &info, &registry->entries[i]);
-
+ if (object_id)
+ *object_id = info.object_id;
+
/* Drop lock and invoke application code */
_dbus_connection_unlock (registry->connection);
@@ -317,8 +321,8 @@ _dbus_object_registry_free_all_unlocked (DBusObjectRegistry *registry)
dbus_bool_t
_dbus_object_registry_test (void)
{
-
-
+ /* FIXME */
+
return TRUE;
}
diff --git a/dbus/dbus-object.c b/dbus/dbus-object.c
index fdd33dd4..262f75ca 100644
--- a/dbus/dbus-object.c
+++ b/dbus/dbus-object.c
@@ -1,10 +1,10 @@
/* -*- mode: C; c-file-style: "gnu" -*- */
-/* dbus-object.c DBusObject type
+/* dbus-object.c Objects
*
* Copyright (C) 2003 Red Hat Inc.
*
* Licensed under the Academic Free License version 1.2
- *
+ *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@@ -14,7 +14,7 @@
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
@@ -25,3 +25,321 @@
#include "dbus-internals.h"
#include "dbus-object.h"
+/**
+ * @defgroup DBusCallbackObjectInternals DBusCallbackObject implementation details
+ * @ingroup DBusInternals
+ * @brief DBusCallbackObject private implementation details.
+ *
+ * The guts of DBusCallbackObject and its methods.
+ *
+ * @{
+ */
+
+_DBUS_DEFINE_GLOBAL_LOCK (callback_object);
+
+/**
+ * @brief Internals of DBusCallbackObject
+ *
+ * Object that can send and receive messages.
+ */
+struct DBusCallbackObject
+{
+ DBusAtomic refcount; /**< reference count */
+ DBusObjectMessageFunction function; /**< callback function */
+ void *user_data; /**< user data for function */
+ DBusFreeFunction free_user_data; /**< free the user data */
+};
+
+static void
+callback_object_registered (DBusObjectInfo *info)
+{
+ DBusCallbackObject *callback = info->object_impl;
+
+ dbus_callback_object_ref (callback);
+}
+
+static void
+callback_object_unregistered (DBusObjectInfo *info)
+{
+ DBusCallbackObject *callback = info->object_impl;
+
+ dbus_callback_object_unref (callback);
+}
+
+static void
+callback_object_message (DBusObjectInfo *info,
+ DBusMessage *message)
+{
+ DBusCallbackObject *callback = info->object_impl;
+
+ if (callback->function)
+ (* callback->function) (info, message);
+}
+
+/** @} */
+
+/**
+ * @defgroup DBusObject DBusObjectInfo, DBusObjectVTable, DBusCallbackObject
+ * @ingroup DBus
+ * @brief support for object instances
+ *
+ * Behind each DBusConnection are object instances. An object instance
+ * may be a GObject (using GLib), a QObject (using Qt), a built-in
+ * object type called DBusCallbackObject, or any other representation
+ * of an object; it's even permissible to have an object that's simply
+ * an integer value or a pointer to a struct.
+ *
+ * Objects are registered with one or more DBusConnection. Registered
+ * objects receive an object ID, represented by the DBusObjectID type.
+ * Object IDs can be passed over a DBusConnection and used by the
+ * remote application to refer to objects. Remote applications can
+ * also refer to objects by dynamically locating objects that support
+ * a particular interface.
+ *
+ * To define an object, you simply provide three callbacks: one to be
+ * called when the object is registered with a new connection, one
+ * to be called when the object is unregistered, and one to be called
+ * when the object receives a message from the peer on the other end
+ * of the DBusConnection. The three callbacks are specified in a
+ * DBusObjectVTable struct.
+ *
+ * The DBusObjectInfo struct is used to pass the object pointer
+ * (object_impl), connection, and object ID to each of the callbacks
+ * in the virtual table. This struct should be treated as read-only.
+ *
+ * DBusCallbackObject is provided for convenience as a way to
+ * implement an object quickly by writing only one callback function,
+ * the callback that processes messages. To use DBusCallbackObject,
+ * simply create one, then call dbus_connection_register_object()
+ * passing in the provided DBusObjectVTable
+ * dbus_callback_object_vtable. This is the simplest possible object;
+ * it simply contains a function to be called whenever a message is
+ * received.
+ *
+ * The DBusCallbackObject will be strong-referenced by the
+ * DBusConnection, so may be unreferenced once it's registered, and
+ * will go away either on unregistration or when the connection is
+ * freed.
+ *
+ * One DBusCallbackObject may be registered with any number of
+ * DBusConnection.
+ *
+ * @{
+ */
+
+/**
+ * @typedef DBusCallbackObject
+ *
+ * Opaque data type representing a callback object.
+ */
+
+static const DBusObjectVTable callback_object_vtable = {
+ callback_object_registered,
+ callback_object_unregistered,
+ callback_object_message
+};
+
+/**
+ * Virtual table for a DBusCallbackObject, used to register the
+ * callback object with dbus_connection_register_object().
+ */
+const DBusObjectVTable* dbus_callback_object_vtable = &callback_object_vtable;
+
+/**
+ * Creates a new callback object. The callback function
+ * may be #NULL for a no-op callback or a callback to
+ * be assigned a function later.
+ *
+ * Use dbus_connection_register_object() along with
+ * dbus_callback_object_vtable to register the callback object with
+ * one or more connections. Each connection will add a reference to
+ * the callback object, so once it's registered it may be unreferenced
+ * with dbus_callback_object_unref().
+ *
+ * @param function function to call to handle a message
+ * @param user_data data to pass to the function
+ * @param free_user_data function to call to free the user data
+ * @returns a new DBusCallbackObject or #NULL if no memory.
+ */
+DBusCallbackObject*
+dbus_callback_object_new (DBusObjectMessageFunction function,
+ void *user_data,
+ DBusFreeFunction free_user_data)
+{
+ DBusCallbackObject *callback;
+
+ callback = dbus_new0 (DBusCallbackObject, 1);
+ if (callback == NULL)
+ return NULL;
+
+ callback->refcount.value = 1;
+ callback->function = function;
+ callback->user_data = user_data;
+ callback->free_user_data = free_user_data;
+
+ return callback;
+}
+
+/**
+ * Increments the reference count on a callback object.
+ *
+ * @param callback the callback
+ */
+void
+dbus_callback_object_ref (DBusCallbackObject *callback)
+{
+ _dbus_return_if_fail (callback != NULL);
+
+ _dbus_atomic_inc (&callback->refcount);
+}
+
+
+/**
+ * Decrements the reference count on a callback object,
+ * freeing the callback if the count reaches 0.
+ *
+ * @param callback the callback
+ */
+void
+dbus_callback_object_unref (DBusCallbackObject *callback)
+{
+ dbus_bool_t last_unref;
+
+ _dbus_return_if_fail (callback != NULL);
+
+ last_unref = (_dbus_atomic_dec (&callback->refcount) == 1);
+
+ if (last_unref)
+ {
+ if (callback->free_user_data)
+ (* callback->free_user_data) (callback->user_data);
+
+ dbus_free (callback);
+ }
+}
+
+/**
+ * Gets the user data for the callback.
+ *
+ * @param callback the callback
+ * @returns the user data
+ */
+void*
+dbus_callback_object_get_data (DBusCallbackObject *callback)
+{
+ void* user_data;
+
+ _dbus_return_val_if_fail (callback != NULL, NULL);
+
+ _DBUS_LOCK (callback_object);
+ user_data = callback->user_data;
+ _DBUS_UNLOCK (callback_object);
+ return user_data;
+}
+
+
+/**
+ * Sets the user data for the callback. Frees any previously-existing
+ * user data with the previous free_user_data function.
+ *
+ * @param callback the callback
+ * @param user_data the user data
+ * @param free_user_data free function for the data
+ */
+void
+dbus_callback_object_set_data (DBusCallbackObject *callback,
+ void *user_data,
+ DBusFreeFunction free_user_data)
+{
+ DBusFreeFunction old_free_func;
+ void *old_user_data;
+
+ _dbus_return_if_fail (callback != NULL);
+
+ _DBUS_LOCK (callback_object);
+ old_free_func = callback->free_user_data;
+ old_user_data = callback->user_data;
+
+ callback->user_data = user_data;
+ callback->free_user_data = free_user_data;
+ _DBUS_UNLOCK (callback_object);
+
+ if (old_free_func)
+ (* old_free_func) (old_user_data);
+}
+
+/**
+ * Sets the function to be used to handle messages to the
+ * callback object.
+ *
+ * @param callback the callback
+ * @param function the function
+ */
+void
+dbus_callback_object_set_function (DBusCallbackObject *callback,
+ DBusObjectMessageFunction function)
+{
+ _dbus_return_if_fail (callback != NULL);
+
+ _DBUS_LOCK (callback_object);
+ callback->function = function;
+ _DBUS_UNLOCK (callback_object);
+}
+
+
+/** @} */
+
+#ifdef DBUS_BUILD_TESTS
+#include "dbus-test.h"
+#include <stdio.h>
+
+static void
+test_message_function (DBusObjectInfo *info,
+ DBusMessage *message)
+{
+ /* nothing */
+}
+
+static void
+free_test_data (void *data)
+{
+ /* does nothing */
+}
+
+/**
+ * @ingroup DBusCallbackObjectInternals
+ * Unit test for DBusCallbackObject.
+ *
+ * @returns #TRUE on success.
+ */
+dbus_bool_t
+_dbus_object_test (void)
+{
+ DBusCallbackObject *callback;
+
+#define TEST_DATA ((void*) 0xcafebabe)
+
+ callback = dbus_callback_object_new (test_message_function,
+ TEST_DATA,
+ free_test_data);
+
+ _dbus_assert (callback != NULL);
+ _dbus_assert (callback->function == test_message_function);
+
+ if (dbus_callback_object_get_data (callback) != TEST_DATA)
+ _dbus_assert_not_reached ("got wrong data");
+
+ dbus_callback_object_set_data (callback, NULL, NULL);
+ if (dbus_callback_object_get_data (callback) != NULL)
+ _dbus_assert_not_reached ("got wrong data after set");
+
+ dbus_callback_object_set_function (callback, NULL);
+ _dbus_assert (callback->function == NULL);
+
+ dbus_callback_object_ref (callback);
+ dbus_callback_object_unref (callback);
+ dbus_callback_object_unref (callback);
+
+ return TRUE;
+}
+#endif /* DBUS_BUILD_TESTS */
diff --git a/dbus/dbus-object.h b/dbus/dbus-object.h
index 0c92776d..b05d9c4b 100644
--- a/dbus/dbus-object.h
+++ b/dbus/dbus-object.h
@@ -1,5 +1,5 @@
/* -*- mode: C; c-file-style: "gnu" -*- */
-/* dbus-object.h DBusObject type
+/* dbus-object.h Objects
*
* Copyright (C) 2003 Red Hat Inc.
*
@@ -29,18 +29,19 @@
#include <dbus/dbus-arch-deps.h>
#include <dbus/dbus-types.h>
+#include <dbus/dbus-message.h>
#include <dbus/dbus-objectid.h>
-#include <dbus/dbus-connection.h>
DBUS_BEGIN_DECLS;
+typedef struct DBusConnection DBusConnection;
typedef struct DBusObjectVTable DBusObjectVTable;
typedef struct DBusObjectInfo DBusObjectInfo;
typedef struct DBusCallbackObject DBusCallbackObject;
struct DBusObjectInfo
{
- void *object_impl;
+ void *object_impl; /**< Object information */
DBusObjectID object_id;
DBusConnection *connection;
};
@@ -57,26 +58,18 @@ struct DBusObjectVTable
DBusObjectMessageFunction message;
};
-dbus_bool_t dbus_connection_register_object (DBusConnection *connection,
- const char **interfaces,
- const DBusObjectVTable *vtable,
- void *object_impl,
- DBusObjectID *object_id);
-void dbus_connection_unregister_object (DBusConnection *connection,
- const DBusObjectID *object_id);
-
extern const DBusObjectVTable *dbus_callback_object_vtable;
DBusCallbackObject* dbus_callback_object_new (DBusObjectMessageFunction function,
void *user_data,
DBusFreeFunction free_user_data);
-void dbus_callback_object_ref (DBusCallbackObject *handler);
-void dbus_callback_object_unref (DBusCallbackObject *handler);
-void* dbus_callback_object_get_data (DBusCallbackObject *handler);
-void dbus_callback_object_set_data (DBusCallbackObject *handler,
+void dbus_callback_object_ref (DBusCallbackObject *callback);
+void dbus_callback_object_unref (DBusCallbackObject *callback);
+void* dbus_callback_object_get_data (DBusCallbackObject *callback);
+void dbus_callback_object_set_data (DBusCallbackObject *callback,
void *data,
DBusFreeFunction free_user_data);
-void dbus_callback_object_set_function (DBusCallbackObject *handler,
+void dbus_callback_object_set_function (DBusCallbackObject *callback,
DBusObjectMessageFunction function);
diff --git a/dbus/dbus-test.c b/dbus/dbus-test.c
index 220961c7..c3b31107 100644
--- a/dbus/dbus-test.c
+++ b/dbus/dbus-test.c
@@ -111,6 +111,12 @@ dbus_internal_do_not_use_run_tests (const char *test_data_dir)
die ("object registry");
check_memleaks ();
+
+ printf ("%s: running object tests\n", "dbus-test");
+ if (!_dbus_object_test ())
+ die ("object");
+
+ check_memleaks ();
printf ("%s: running marshalling tests\n", "dbus-test");
if (!_dbus_marshal_test ())
diff --git a/dbus/dbus-test.h b/dbus/dbus-test.h
index c9555e2d..8537be40 100644
--- a/dbus/dbus-test.h
+++ b/dbus/dbus-test.h
@@ -53,6 +53,7 @@ dbus_bool_t _dbus_sysdeps_test (void);
dbus_bool_t _dbus_spawn_test (const char *test_data_dir);
dbus_bool_t _dbus_userdb_test (const char *test_data_dir);
dbus_bool_t _dbus_memory_test (void);
+dbus_bool_t _dbus_object_test (void);
dbus_bool_t _dbus_object_id_test (void);
dbus_bool_t _dbus_object_registry_test (void);
diff --git a/dbus/dbus-threads.c b/dbus/dbus-threads.c
index b604a397..81c3fbfe 100644
--- a/dbus/dbus-threads.c
+++ b/dbus/dbus-threads.c
@@ -227,6 +227,7 @@ init_global_locks (void)
LOCK_ADDR (message_slots),
LOCK_ADDR (atomic),
LOCK_ADDR (message_handler),
+ LOCK_ADDR (callback_object),
LOCK_ADDR (bus),
LOCK_ADDR (shutdown_funcs),
LOCK_ADDR (system_users)