2003-07-08 Havoc Pennington <hp@pobox.com>
authorHavoc Pennington <hp@redhat.com>
Wed, 9 Jul 2003 03:41:00 +0000 (03:41 +0000)
committerHavoc Pennington <hp@redhat.com>
Wed, 9 Jul 2003 03:41:00 +0000 (03:41 +0000)
* 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

12 files changed:
ChangeLog
dbus/dbus-connection.c
dbus/dbus-connection.h
dbus/dbus-internals.h
dbus/dbus-message-handler.c
dbus/dbus-message.h
dbus/dbus-object-registry.c
dbus/dbus-object.c
dbus/dbus-object.h
dbus/dbus-test.c
dbus/dbus-test.h
dbus/dbus-threads.c

index 9ed9055..6cf6531 100644 (file)
--- 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 
index 237c195..ed29edc 100644 (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);
 
index ce57c98..6c0da92 100644 (file)
 #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,
index d84017d..7acda71 100644 (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);
 
index f38e510..8bb4dd1 100644 (file)
@@ -325,7 +325,7 @@ free_test_data (void *data)
 }
 
 /**
- * @ingroup DBusMessageInternals
+ * @ingroup DBusMessageHandlerInternals
  * Unit test for DBusMessageHandler.
  *
  * @returns #TRUE on success.
index 9f07565..bd52bd1 100644 (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;
index 9f7ca3f..eba2d8f 100644 (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;
 }
 
index fdd33dd..262f75c 100644 (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
 #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 */
index 0c92776..b05d9c4 100644 (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.
  *
 
 #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);
 
 
index 220961c..c3b3110 100644 (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 ())
index c9555e2..8537be4 100644 (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);
 
index b604a39..81c3fbf 100644 (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)