From d8abf955f5bff3e83cabd267883039f7a42c98c3 Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Tue, 8 Jul 2003 05:07:32 +0000 Subject: 2003-07-08 Havoc Pennington * 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 any conceivable way. * dbus/dbus-object-registry.c: implement the hard bits of the DBusConnection aspect of object API. Not yet wired up. --- dbus/Makefile.am | 4 + dbus/dbus-connection-internal.h | 1 + dbus/dbus-connection.c | 16 ++ dbus/dbus-connection.h | 1 + dbus/dbus-object-registry.c | 325 ++++++++++++++++++++++++++++++++++++++++ dbus/dbus-object-registry.h | 50 +++++++ dbus/dbus-object.c | 27 ++++ dbus/dbus-object.h | 85 +++++++++++ dbus/dbus-objectid.h | 4 + dbus/dbus-test.c | 6 + dbus/dbus-test.h | 1 + dbus/dbus.h | 1 + 12 files changed, 521 insertions(+) create mode 100644 dbus/dbus-object-registry.c create mode 100644 dbus/dbus-object-registry.h create mode 100644 dbus/dbus-object.c create mode 100644 dbus/dbus-object.h (limited to 'dbus') diff --git a/dbus/Makefile.am b/dbus/Makefile.am index 3c3c14e7..8c919f31 100644 --- a/dbus/Makefile.am +++ b/dbus/Makefile.am @@ -17,6 +17,7 @@ dbusinclude_HEADERS= \ dbus-memory.h \ dbus-message.h \ dbus-message-handler.h \ + dbus-object.h \ dbus-objectid.h \ dbus-protocol.h \ dbus-server.h \ @@ -43,7 +44,10 @@ DBUS_LIB_SOURCES= \ dbus-message.c \ dbus-message-handler.c \ dbus-message-internal.h \ + dbus-object.c \ dbus-objectid.c \ + dbus-object-registry.c \ + dbus-object-registry.h \ dbus-resources.c \ dbus-resources.h \ dbus-server.c \ diff --git a/dbus/dbus-connection-internal.h b/dbus/dbus-connection-internal.h index 5ddc0e0a..eaa35955 100644 --- a/dbus/dbus-connection-internal.h +++ b/dbus/dbus-connection-internal.h @@ -81,6 +81,7 @@ void _dbus_message_handler_remove_connection (DBusMessageHandl DBusHandlerResult _dbus_message_handler_handle_message (DBusMessageHandler *handler, DBusConnection *connection, DBusMessage *message); +dbus_uint32_t _dbus_connection_get_id (DBusConnection *connection); DBUS_END_DECLS; diff --git a/dbus/dbus-connection.c b/dbus/dbus-connection.c index 01b2a7bf..237c195b 100644 --- a/dbus/dbus-connection.c +++ b/dbus/dbus-connection.c @@ -920,6 +920,22 @@ _dbus_connection_handle_watch (DBusWatch *watch, return retval; } +/** + * Get the ID to be used in the high bits of an object ID for an object + * registered with this connection. + * + * @todo implement this function + * + * @param connection the connection. + * @returns the connection portion of the object ID + */ +dbus_uint32_t +_dbus_connection_get_id (DBusConnection *connection) +{ + /* FIXME */ + return 1492; +} + /** @} */ /** diff --git a/dbus/dbus-connection.h b/dbus/dbus-connection.h index 9f4dd7ae..ce57c98d 100644 --- a/dbus/dbus-connection.h +++ b/dbus/dbus-connection.h @@ -37,6 +37,7 @@ typedef struct DBusConnection DBusConnection; typedef struct DBusWatch DBusWatch; typedef struct DBusTimeout DBusTimeout; typedef struct DBusMessageHandler DBusMessageHandler; +typedef struct DBusObject DBusObject; typedef struct DBusPreallocatedSend DBusPreallocatedSend; typedef enum diff --git a/dbus/dbus-object-registry.c b/dbus/dbus-object-registry.c new file mode 100644 index 00000000..9f7ca3ff --- /dev/null +++ b/dbus/dbus-object-registry.c @@ -0,0 +1,325 @@ +/* -*- mode: C; c-file-style: "gnu" -*- */ +/* dbus-object-registry.c DBusObjectRegistry (internals of DBusConnection) + * + * 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 + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * 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 + * + */ +#include "dbus-object-registry.h" +#include "dbus-connection-internal.h" +#include "dbus-internals.h" +#include + +/** + * @defgroup DBusObjectRegistry Map object IDs to implementations + * @ingroup DBusInternals + * @brief DBusObjectRegistry is used by DBusConnection to track object IDs + * + * Types and functions related to DBusObjectRegistry + * + * @{ + */ + +typedef struct DBusObjectEntry DBusObjectEntry; + + /* 14 bits for object index, 32K objects */ +#define DBUS_OBJECT_INDEX_BITS (14) +#define DBUS_OBJECT_INDEX_MASK (0x7fff) +#define DBUS_MAX_OBJECTS_PER_CONNECTION DBUS_OBJECT_INDEX_MASK +struct DBusObjectEntry +{ + unsigned int id_index : 14; /**< Index of this entry in the entries array */ + unsigned int id_times_used : 18; /**< Count of times entry has been used; avoids recycling IDs too often */ + + void *object_impl; /**< Pointer to application-supplied implementation */ + const DBusObjectVTable *vtable; /**< Virtual table for this object */ +}; + +struct DBusObjectRegistry +{ + int refcount; + DBusConnection *connection; + + DBusObjectEntry *entries; + int n_entries_allocated; + int n_entries_used; +}; + +DBusObjectRegistry* +_dbus_object_registry_new (DBusConnection *connection) +{ + DBusObjectRegistry *registry; + + registry = dbus_new0 (DBusObjectRegistry, 1); + + registry->refcount = 1; + registry->connection = connection; + + return registry; +} + +void +_dbus_object_registry_ref (DBusObjectRegistry *registry) +{ + _dbus_assert (registry->refcount > 0); + + registry->refcount += 1; +} + +void +_dbus_object_registry_unref (DBusObjectRegistry *registry) +{ + _dbus_assert (registry->refcount > 0); + + registry->refcount -= 1; + + if (registry->refcount == 0) + { + _dbus_assert (registry->n_entries_used == 0); + + dbus_free (registry->entries); + dbus_free (registry); + } +} + +#define ENTRY_TO_ID(entry) \ + (((dbus_uint32_t) (entry)->id_index) | \ + (((dbus_uint32_t)(entry)->id_times_used) << DBUS_OBJECT_INDEX_BITS)) + +#define ID_TO_INDEX(id) \ + (((dbus_uint32_t) (id)) | DBUS_OBJECT_INDEX_MASK) + +#define ID_TO_TIMES_USED(id) \ + (((dbus_uint32_t) (id)) >> DBUS_OBJECT_INDEX_BITS) + +static DBusObjectEntry* +validate_id (DBusObjectRegistry *registry, + const DBusObjectID *object_id) +{ + int idx; + int times_used; + dbus_uint32_t low_bits; + + low_bits = dbus_object_id_get_low_bits (object_id); + + idx = ID_TO_INDEX (low_bits); + times_used = ID_TO_TIMES_USED (low_bits); + + if (idx >= registry->n_entries_allocated) + return NULL; + if (registry->entries[idx].vtable == NULL) + return NULL; + if (registry->entries[idx].id_times_used != times_used) + return NULL; + _dbus_assert (registry->entries[idx].id_index == idx); + _dbus_assert (registry->n_entries_used > 0); + + return ®istry->entries[idx]; +} + +static void +info_from_entry (DBusObjectRegistry *registry, + DBusObjectInfo *info, + DBusObjectEntry *entry) +{ + info->connection = registry->connection; + info->object_impl = entry->object_impl; + dbus_object_id_set_high_bits (&info->object_id, + _dbus_connection_get_id (registry->connection)); + dbus_object_id_set_low_bits (&info->object_id, + ENTRY_TO_ID (entry)); +} + +dbus_bool_t +_dbus_object_registry_add_and_unlock (DBusObjectRegistry *registry, + const char **interfaces, + const DBusObjectVTable *vtable, + void *object_impl, + DBusObjectID *object_id) +{ + int i; + DBusObjectInfo info; + + if (registry->n_entries_used == registry->n_entries_allocated) + { + DBusObjectEntry *new_entries; + int new_alloc; + + if (registry->n_entries_allocated == 0) + new_alloc = 16; + else + { + if (registry->n_entries_allocated == DBUS_MAX_OBJECTS_PER_CONNECTION) + { + _dbus_warn ("Attempting to register a new D-BUS object, but maximum object count of %d reached\n", + DBUS_MAX_OBJECTS_PER_CONNECTION); + return FALSE; + } + + new_alloc = registry->n_entries_allocated * 2; + if (new_alloc > DBUS_MAX_OBJECTS_PER_CONNECTION) + new_alloc = DBUS_MAX_OBJECTS_PER_CONNECTION; + } + + new_entries = dbus_realloc (registry->entries, + new_alloc * sizeof (DBusObjectEntry)); + + if (new_entries == NULL) + return FALSE; + + memset (&new_entries[registry->n_entries_allocated], + '\0', + sizeof (DBusObjectEntry) * (new_alloc - registry->n_entries_allocated)); + + registry->entries = new_entries; + registry->n_entries_allocated = new_alloc; + } + _dbus_assert (registry->n_entries_used < registry->n_entries_allocated); + + /* We linear search for an available entry. However, short-circuit + * the hopefully-common situation where we don't have a sparse + * array. + */ + if (registry->entries[registry->n_entries_used].vtable == NULL) + { + i = registry->n_entries_used; + } + else + { + /* If we do have a sparse array, we try to get rid of it rather + * than using empty slots on the end, so we won't hit this case + * next time. + */ + + /* If index n_entries_used is occupied, then + * there is at least one entry outside of + * the range [0, n_entries_used). Thus, there is + * at least one blank entry inside that range. + */ + i = 0; + while (i < registry->n_entries_used) + { + if (registry->entries[i].vtable == NULL) + break; + ++i; + } + + _dbus_assert (i < registry->n_entries_used); + } + + registry->entries[i].id_index = i; + /* Overflow is OK here */ + registry->entries[i].id_times_used += 1; + + registry->entries[i].vtable = vtable; + registry->entries[i].object_impl = object_impl; + + info_from_entry (registry, &info, ®istry->entries[i]); + + /* Drop lock and invoke application code */ + _dbus_connection_unlock (registry->connection); + + (* vtable->registered) (&info); + + return TRUE; +} + +void +_dbus_object_registry_remove_and_unlock (DBusObjectRegistry *registry, + const DBusObjectID *object_id) +{ + DBusObjectInfo info; + DBusObjectEntry *entry; + const DBusObjectVTable *vtable; + + entry = validate_id (registry, object_id); + if (entry == NULL) + { + _dbus_warn ("Tried to unregister a nonexistent D-BUS object ID\n"); + return; + } + + info_from_entry (registry, &info, entry); + vtable = entry->vtable; + entry->vtable = NULL; + entry->object_impl = NULL; + registry->n_entries_used -= 1; + + /* Drop lock and invoke application code */ + _dbus_connection_unlock (registry->connection); + + (* vtable->unregistered) (&info); +} + +void +_dbus_object_registry_handle_and_unlock (DBusObjectRegistry *registry, + DBusMessage *message) +{ + /* FIXME */ +} + +void +_dbus_object_registry_free_all_unlocked (DBusObjectRegistry *registry) +{ + int i; + + i = 0; + while (registry->n_entries_used > 0) + { + _dbus_assert (i < registry->n_entries_allocated); + if (registry->entries[i].vtable != NULL) + { + DBusObjectInfo info; + const DBusObjectVTable *vtable; + + info_from_entry (registry, &info, ®istry->entries[i]); + vtable = registry->entries[i].vtable; + registry->entries[i].vtable = NULL; + registry->entries[i].object_impl = NULL; + registry->n_entries_used -= 1; + _dbus_assert (registry->n_entries_used >= 0); + + (* vtable->unregistered) (&info); + } + + ++i; + } + + _dbus_assert (registry->n_entries_used == 0); +} + +/** @} */ + +#ifdef DBUS_BUILD_TESTS +#include "dbus-test.h" +#include + +/** + * @ingroup DBusObjectRegistry + * Unit test for DBusObjectRegistry + * @returns #TRUE on success. + */ +dbus_bool_t +_dbus_object_registry_test (void) +{ + + + return TRUE; +} + +#endif /* DBUS_BUILD_TESTS */ diff --git a/dbus/dbus-object-registry.h b/dbus/dbus-object-registry.h new file mode 100644 index 00000000..d33664e5 --- /dev/null +++ b/dbus/dbus-object-registry.h @@ -0,0 +1,50 @@ +/* -*- mode: C; c-file-style: "gnu" -*- */ +/* dbus-object-registry.h DBusObjectRegistry (internals of DBusConnection) + * + * 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 + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * 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 + * + */ +#ifndef DBUS_OBJECT_REGISTRY_H +#define DBUS_OBJECT_REGISTRY_H + +#include + +DBUS_BEGIN_DECLS; + +typedef struct DBusObjectRegistry DBusObjectRegistry; + +DBusObjectRegistry* _dbus_object_registry_new (DBusConnection *connection); +void _dbus_object_registry_ref (DBusObjectRegistry *registry); +void _dbus_object_registry_unref (DBusObjectRegistry *registry); + +dbus_bool_t _dbus_object_registry_add_and_unlock (DBusObjectRegistry *registry, + const char **interfaces, + const DBusObjectVTable *vtable, + void *object_impl, + DBusObjectID *object_id); +void _dbus_object_registry_remove_and_unlock (DBusObjectRegistry *registry, + const DBusObjectID *object_id); +void _dbus_object_registry_handle_and_unlock (DBusObjectRegistry *registry, + DBusMessage *message); +void _dbus_object_registry_free_all_unlocked (DBusObjectRegistry *registry); + + +DBUS_END_DECLS; + +#endif /* DBUS_OBJECT_REGISTRY_H */ diff --git a/dbus/dbus-object.c b/dbus/dbus-object.c new file mode 100644 index 00000000..fdd33dd4 --- /dev/null +++ b/dbus/dbus-object.c @@ -0,0 +1,27 @@ +/* -*- mode: C; c-file-style: "gnu" -*- */ +/* dbus-object.c DBusObject type + * + * 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 + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * 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 + * + */ + +#include +#include "dbus-internals.h" +#include "dbus-object.h" + diff --git a/dbus/dbus-object.h b/dbus/dbus-object.h new file mode 100644 index 00000000..0c92776d --- /dev/null +++ b/dbus/dbus-object.h @@ -0,0 +1,85 @@ +/* -*- mode: C; c-file-style: "gnu" -*- */ +/* dbus-object.h DBusObject type + * + * 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 + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * 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 + * + */ +#if !defined (DBUS_INSIDE_DBUS_H) && !defined (DBUS_COMPILATION) +#error "Only can be included directly, this file may disappear or change contents." +#endif + +#ifndef DBUS_OBJECT_H +#define DBUS_OBJECT_H + +#include +#include +#include +#include + +DBUS_BEGIN_DECLS; + +typedef struct DBusObjectVTable DBusObjectVTable; +typedef struct DBusObjectInfo DBusObjectInfo; +typedef struct DBusCallbackObject DBusCallbackObject; + +struct DBusObjectInfo +{ + void *object_impl; + DBusObjectID object_id; + DBusConnection *connection; +}; + +typedef void (* DBusObjectRegisteredFunction) (DBusObjectInfo *info); +typedef void (* DBusObjectUnregisteredFunction) (DBusObjectInfo *info); +typedef void (* DBusObjectMessageFunction) (DBusObjectInfo *info, + DBusMessage *message); + +struct DBusObjectVTable +{ + DBusObjectRegisteredFunction registered; + DBusObjectUnregisteredFunction unregistered; + 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 *data, + DBusFreeFunction free_user_data); +void dbus_callback_object_set_function (DBusCallbackObject *handler, + DBusObjectMessageFunction function); + + +DBUS_END_DECLS; + +#endif /* DBUS_OBJECT_H */ diff --git a/dbus/dbus-objectid.h b/dbus/dbus-objectid.h index 57346910..b5e1f606 100644 --- a/dbus/dbus-objectid.h +++ b/dbus/dbus-objectid.h @@ -30,6 +30,8 @@ #include #include +DBUS_BEGIN_DECLS; + typedef struct DBusObjectID DBusObjectID; struct DBusObjectID @@ -58,4 +60,6 @@ void dbus_object_id_set_as_integer (DBusObjectID *obj_id dbus_uint64_t value); #endif +DBUS_END_DECLS; + #endif /* DBUS_OBJECTID_H */ diff --git a/dbus/dbus-test.c b/dbus/dbus-test.c index 3d5d14bb..220961c7 100644 --- a/dbus/dbus-test.c +++ b/dbus/dbus-test.c @@ -105,6 +105,12 @@ dbus_internal_do_not_use_run_tests (const char *test_data_dir) die ("object ID"); check_memleaks (); + + printf ("%s: running object registry tests\n", "dbus-test"); + if (!_dbus_object_registry_test ()) + die ("object registry"); + + 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 512cb9a6..c9555e2d 100644 --- a/dbus/dbus-test.h +++ b/dbus/dbus-test.h @@ -54,6 +54,7 @@ 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_id_test (void); +dbus_bool_t _dbus_object_registry_test (void); void dbus_internal_do_not_use_run_tests (const char *test_data_dir); diff --git a/dbus/dbus.h b/dbus/dbus.h index 38db4f5b..d83a4a50 100644 --- a/dbus/dbus.h +++ b/dbus/dbus.h @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include -- cgit