From 824d4a5edfe1fa7222ab5cb49928bf78a675b563 Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Wed, 9 Jul 2003 03:41:00 +0000 Subject: 2003-07-08 Havoc Pennington * 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 --- ChangeLog | 9 ++ dbus/dbus-connection.c | 45 ++++++ dbus/dbus-connection.h | 13 +- dbus/dbus-internals.h | 3 +- dbus/dbus-message-handler.c | 2 +- dbus/dbus-message.h | 1 + dbus/dbus-object-registry.c | 12 +- dbus/dbus-object.c | 324 +++++++++++++++++++++++++++++++++++++++++++- dbus/dbus-object.h | 25 ++-- dbus/dbus-test.c | 6 + dbus/dbus-test.h | 1 + dbus/dbus-threads.c | 1 + 12 files changed, 415 insertions(+), 27 deletions(-) diff --git a/ChangeLog b/ChangeLog index 9ed9055c..6cf65315 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2003-07-08 Havoc Pennington + + * 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 * dbus/dbus-object.h: sketch out an API for registering objects 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 -#include #include +#include 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 #include #include +#include #include 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, ®istry->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 + +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 #include +#include #include -#include 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) -- cgit v1.2.1