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
This commit is contained in:
Havoc Pennington 2003-07-09 03:41:00 +00:00
parent d8abf955f5
commit 824d4a5edf
12 changed files with 415 additions and 27 deletions

View file

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

View file

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

View file

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

View file

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

View file

@ -325,7 +325,7 @@ free_test_data (void *data)
}
/**
* @ingroup DBusMessageInternals
* @ingroup DBusMessageHandlerInternals
* Unit test for DBusMessageHandler.
*
* @returns #TRUE on success.

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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