2003-04-03 Havoc Pennington <hp@redhat.com>
authorHavoc Pennington <hp@redhat.com>
Fri, 4 Apr 2003 00:39:22 +0000 (00:39 +0000)
committerHavoc Pennington <hp@redhat.com>
Fri, 4 Apr 2003 00:39:22 +0000 (00:39 +0000)
* bus/loop.h, bus/loop.c: make the mainloop an object so we can
have multiple ones

* bus/*.[hc]: adapt to mainloop change

ChangeLog
bus/bus.c
bus/bus.h
bus/connection.c
bus/dispatch.c
bus/loop.c
bus/loop.h
bus/main.c
bus/test.c
bus/test.h
doc/TODO

index a164df0..363fc3c 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,12 @@
 2003-04-03  Havoc Pennington  <hp@redhat.com>
 
+       * bus/loop.h, bus/loop.c: make the mainloop an object so we can
+       have multiple ones
+
+       * bus/*.[hc]: adapt to mainloop change
+
+2003-04-03  Havoc Pennington  <hp@redhat.com>
+
        * bus/activation.c (load_directory): fix up memleaks
        (bus_activation_entry_free): free the entry
 
index 381f631..9125fc7 100644 (file)
--- a/bus/bus.c
+++ b/bus/bus.c
@@ -38,6 +38,7 @@ struct BusContext
   int refcount;
   char *type;
   char *address;
+  BusLoop *loop;
   DBusList *servers;
   BusConnections *connections;
   BusActivation *activation;
@@ -48,6 +49,68 @@ struct BusContext
   DBusHashTable *rules_by_gid;  /**< per-GID policy rules */
 };
 
+static int server_data_slot = -1;
+static int server_data_slot_refcount = 0;
+
+typedef struct
+{
+  BusContext *context;
+} BusServerData;
+
+#define BUS_SERVER_DATA(server) (dbus_server_get_data ((server), server_data_slot))
+
+static dbus_bool_t
+server_data_slot_ref (void)
+{
+  if (server_data_slot < 0)
+    {
+      server_data_slot = dbus_server_allocate_data_slot ();
+      
+      if (server_data_slot < 0)
+        return FALSE;
+
+      _dbus_assert (server_data_slot_refcount == 0);
+    }  
+
+  server_data_slot_refcount += 1;
+
+  return TRUE;
+}
+
+static void
+server_data_slot_unref (void)
+{
+  _dbus_assert (server_data_slot_refcount > 0);
+
+  server_data_slot_refcount -= 1;
+  
+  if (server_data_slot_refcount == 0)
+    {
+      dbus_server_free_data_slot (server_data_slot);
+      server_data_slot = -1;
+    }
+}
+
+static BusContext*
+server_get_context (DBusServer *server)
+{
+  BusContext *context;
+  BusServerData *bd;
+  
+  if (!server_data_slot_ref ())
+    return NULL;
+
+  bd = BUS_SERVER_DATA (server);
+  if (bd == NULL)
+    return NULL;
+
+  context = bd->context;
+
+  server_data_slot_unref ();
+
+  return context;
+}
+
 static dbus_bool_t
 server_watch_callback (DBusWatch     *watch,
                        unsigned int   condition,
@@ -62,7 +125,13 @@ static dbus_bool_t
 add_server_watch (DBusWatch  *watch,
                   void       *data)
 {
-  return bus_loop_add_watch (watch, server_watch_callback, data,
+  DBusServer *server = data;
+  BusContext *context;
+  
+  context = server_get_context (server);
+  
+  return bus_loop_add_watch (context->loop,
+                             watch, server_watch_callback, server,
                              NULL);
 }
 
@@ -70,7 +139,13 @@ static void
 remove_server_watch (DBusWatch  *watch,
                      void       *data)
 {
-  bus_loop_remove_watch (watch, server_watch_callback, data);
+  DBusServer *server = data;
+  BusContext *context;
+  
+  context = server_get_context (server);
+  
+  bus_loop_remove_watch (context->loop,
+                         watch, server_watch_callback, server);
 }
 
 
@@ -86,14 +161,26 @@ static dbus_bool_t
 add_server_timeout (DBusTimeout *timeout,
                     void        *data)
 {
-  return bus_loop_add_timeout (timeout, server_timeout_callback, data, NULL);
+  DBusServer *server = data;
+  BusContext *context;
+  
+  context = server_get_context (server);
+
+  return bus_loop_add_timeout (context->loop,
+                               timeout, server_timeout_callback, server, NULL);
 }
 
 static void
 remove_server_timeout (DBusTimeout *timeout,
                        void        *data)
 {
-  bus_loop_remove_timeout (timeout, server_timeout_callback, data);
+  DBusServer *server = data;
+  BusContext *context;
+  
+  context = server_get_context (server);
+  
+  bus_loop_remove_timeout (context->loop,
+                           timeout, server_timeout_callback, server);
 }
 
 static void
@@ -139,12 +226,22 @@ free_rule_list_func (void *data)
   dbus_free (list);
 }
 
+static void
+free_server_data (void *data)
+{
+  BusServerData *bd = data;  
+  
+  dbus_free (bd);
+}
+
 static dbus_bool_t
 setup_server (BusContext *context,
               DBusServer *server,
               char      **auth_mechanisms,
               DBusError  *error)
 {
+  BusServerData *bd;
+  
   if (!dbus_server_set_auth_mechanisms (server, (const char**) auth_mechanisms))
     {
       BUS_SET_OOM (error);
@@ -175,7 +272,18 @@ setup_server (BusContext *context,
       BUS_SET_OOM (error);
       return FALSE;
     }
+  
+  bd = dbus_new0 (BusServerData, 1);
+  if (!dbus_server_set_data (server,
+                             server_data_slot,
+                             bd, free_server_data))
+    {
+      dbus_free (bd);
+      return FALSE;
+    }
 
+  bd->context = context;
+  
   return TRUE;
 }
 
@@ -196,8 +304,18 @@ bus_context_new (const DBusString *config_file,
   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
 
   if (!_dbus_string_init (&full_address))
-    return NULL;
-
+    {
+      BUS_SET_OOM (error);
+      return NULL;
+    }
+  
+  if (!server_data_slot_ref ())
+    {
+      BUS_SET_OOM (error);
+      _dbus_string_free (&full_address);
+      return NULL;
+    }
+  
   parser = NULL;
   context = NULL;
   auth_mechanisms = NULL;
@@ -215,6 +333,13 @@ bus_context_new (const DBusString *config_file,
   
   context->refcount = 1;
 
+  context->loop = bus_loop_new ();
+  if (context->loop == NULL)
+    {
+      BUS_SET_OOM (error);
+      goto failed;
+    }
+  
   /* Build an array of auth mechanisms */
   
   auth_mechanisms_list = bus_config_parser_get_mechanisms (parser);
@@ -401,6 +526,9 @@ bus_context_new (const DBusString *config_file,
 
   _dbus_string_free (&full_address);
   dbus_free_string_array (auth_mechanisms);
+
+  server_data_slot_unref ();
+  
   return NULL;
 }
 
@@ -501,9 +629,17 @@ bus_context_unref (BusContext *context)
           context->rules_by_gid = NULL;
         }
 
+      if (context->loop)
+        {
+          bus_loop_unref (context->loop);
+          context->loop = NULL;
+        }
+      
       dbus_free (context->type);
       dbus_free (context->address);
       dbus_free (context);
+
+      server_data_slot_unref ();
     }
 }
 
@@ -532,6 +668,12 @@ bus_context_get_activation (BusContext  *context)
   return context->activation;
 }
 
+BusLoop*
+bus_context_get_loop (BusContext *context)
+{
+  return context->loop;
+}
+
 static dbus_bool_t
 list_allows_user (dbus_bool_t           def,
                   DBusList            **list,
index 902f5fa..8357f7b 100644 (file)
--- a/bus/bus.h
+++ b/bus/bus.h
@@ -29,6 +29,8 @@
 #include <dbus/dbus.h>
 #include <dbus/dbus-string.h>
 
+#include "loop.h"
+
 typedef struct BusActivation  BusActivation;
 typedef struct BusConnections BusConnections;
 typedef struct BusContext     BusContext;
@@ -47,6 +49,7 @@ const char*     bus_context_get_type                 (BusContext       *context)
 BusRegistry*    bus_context_get_registry             (BusContext       *context);
 BusConnections* bus_context_get_connections          (BusContext       *context);
 BusActivation*  bus_context_get_activation           (BusContext       *context);
+BusLoop*        bus_context_get_loop                 (BusContext       *context);
 dbus_bool_t     bus_context_allow_user               (BusContext       *context,
                                                       unsigned long     uid);
 BusPolicy*      bus_context_create_connection_policy (BusContext       *context,
index 3c43200..aa8d65c 100644 (file)
@@ -89,6 +89,16 @@ connection_data_slot_unref (void)
     }
 }
 
+static BusLoop*
+connection_get_loop (DBusConnection *connection)
+{
+  BusConnectionData *d;
+
+  d = BUS_CONNECTION_DATA (connection);
+
+  return bus_context_get_loop (d->connections->context);
+}
+
 void
 bus_connection_disconnected (DBusConnection *connection)
 {
@@ -195,17 +205,23 @@ connection_watch_callback (DBusWatch     *watch,
 
 static dbus_bool_t
 add_connection_watch (DBusWatch      *watch,
-                      DBusConnection *connection)
+                      void           *data)
 {
-  return bus_loop_add_watch (watch, connection_watch_callback, connection,
+  DBusConnection *connection = data;
+
+  return bus_loop_add_watch (connection_get_loop (connection),
+                             watch, connection_watch_callback, connection,
                              NULL);
 }
 
 static void
 remove_connection_watch (DBusWatch      *watch,
-                         DBusConnection *connection)
+                         void           *data)
 {
-  bus_loop_remove_watch (watch, connection_watch_callback, connection);
+  DBusConnection *connection = data;
+  
+  bus_loop_remove_watch (connection_get_loop (connection),
+                         watch, connection_watch_callback, connection);
 }
 
 static void
@@ -226,16 +242,22 @@ connection_timeout_callback (DBusTimeout   *timeout,
 
 static dbus_bool_t
 add_connection_timeout (DBusTimeout    *timeout,
-                        DBusConnection *connection)
+                        void           *data)
 {
-  return bus_loop_add_timeout (timeout, connection_timeout_callback, connection, NULL);
+  DBusConnection *connection = data;
+  
+  return bus_loop_add_timeout (connection_get_loop (connection),
+                               timeout, connection_timeout_callback, connection, NULL);
 }
 
 static void
 remove_connection_timeout (DBusTimeout    *timeout,
-                           DBusConnection *connection)
+                           void           *data)
 {
-  bus_loop_remove_timeout (timeout, connection_timeout_callback, connection);
+  DBusConnection *connection = data;
+  
+  bus_loop_remove_timeout (connection_get_loop (connection),
+                           timeout, connection_timeout_callback, connection);
 }
 
 static dbus_bool_t
@@ -366,16 +388,16 @@ bus_connections_setup_connection (BusConnections *connections,
   d->group_ids = NULL;
   
   if (!dbus_connection_set_watch_functions (connection,
-                                            (DBusAddWatchFunction) add_connection_watch,
-                                            (DBusRemoveWatchFunction) remove_connection_watch,
+                                            add_connection_watch,
+                                            remove_connection_watch,
                                             NULL,
                                             connection,
                                             NULL))
     goto out;
   
   if (!dbus_connection_set_timeout_functions (connection,
-                                              (DBusAddTimeoutFunction) add_connection_timeout,
-                                              (DBusRemoveTimeoutFunction) remove_connection_timeout,
+                                              add_connection_timeout,
+                                              remove_connection_timeout,
                                               NULL,
                                               connection, NULL))
     goto out;
@@ -400,12 +422,7 @@ bus_connections_setup_connection (BusConnections *connections,
 
  out:
   if (!retval)
-    {
-      if (!dbus_connection_set_data (connection,
-                                     connection_data_slot,
-                                     NULL, NULL))
-        _dbus_assert_not_reached ("failed to set connection data to null");
-        
+    {        
       if (!dbus_connection_set_watch_functions (connection,
                                                 NULL, NULL, NULL,
                                                 connection,
@@ -420,6 +437,11 @@ bus_connections_setup_connection (BusConnections *connections,
 
       dbus_connection_set_unix_user_function (connection,
                                               NULL, NULL, NULL);
+
+      if (!dbus_connection_set_data (connection,
+                                     connection_data_slot,
+                                     NULL, NULL))
+        _dbus_assert_not_reached ("failed to set connection data to null");
     }
   
   return retval;
index 7c65ac4..21d57ae 100644 (file)
@@ -537,8 +537,8 @@ kill_client_connection (BusContext     *context,
   /* kick in the disconnect handler that unrefs the connection */
   dbus_connection_disconnect (connection);
 
-  bus_test_flush_bus (context);
-
+  bus_test_run_everything (context);
+  
   _dbus_assert (bus_test_client_listed (connection));
   
   /* Run disconnect handler in test.c */
@@ -729,8 +729,8 @@ check_hello_message (BusContext     *context,
 
   dbus_message_unref (message);
   message = NULL;
-  
-  bus_test_flush_bus (context);
+
+  bus_test_run_everything (context);
 
   if (!dbus_connection_get_is_connected (connection))
     {
@@ -963,8 +963,8 @@ check_nonexistent_service_activation (BusContext     *context,
 
   dbus_message_unref (message);
   message = NULL;
-  
-  bus_test_flush_bus (context);
+
+  bus_test_run_everything (context);
 
   if (!dbus_connection_get_is_connected (connection))
     {
@@ -1028,6 +1028,116 @@ check_nonexistent_service_activation (BusContext     *context,
   return retval;
 }
 
+#define EXISTENT_SERVICE_NAME "org.freedesktop.DBus.TestSuiteEchoService"
+
+/* returns TRUE if the correct thing happens,
+ * but the correct thing may include OOM errors.
+ */
+static dbus_bool_t
+check_existent_service_activation (BusContext     *context,
+                                   DBusConnection *connection)
+{
+  DBusMessage *message;
+  dbus_int32_t serial;
+  dbus_bool_t retval;
+  DBusError error;
+  
+  dbus_error_init (&error);
+  
+  message = dbus_message_new (DBUS_SERVICE_DBUS,
+                             DBUS_MESSAGE_ACTIVATE_SERVICE);
+
+  if (message == NULL)
+    return TRUE;
+
+  if (!dbus_message_append_args (message,
+                                 DBUS_TYPE_STRING, EXISTENT_SERVICE_NAME,
+                                 DBUS_TYPE_UINT32, 0,
+                                 DBUS_TYPE_INVALID))
+    {
+      dbus_message_unref (message);
+      return TRUE;
+    }
+  
+  if (!dbus_connection_send (connection, message, &serial))
+    {
+      dbus_message_unref (message);
+      return TRUE;
+    }
+
+  dbus_message_unref (message);
+  message = NULL;
+
+  bus_test_run_everything (context);
+
+  /* now wait for the message bus to hear back from the activated service */
+  bus_test_run_bus_loop (context);
+
+  /* and process everything again */
+  bus_test_run_everything (context);
+
+  if (!dbus_connection_get_is_connected (connection))
+    {
+      _dbus_verbose ("connection was disconnected\n");
+      return TRUE;
+    }
+  
+  retval = FALSE;
+  
+  message = dbus_connection_pop_message (connection);
+  if (message == NULL)
+    {
+      _dbus_warn ("Did not receive a reply to %s %d on %p\n",
+                  DBUS_MESSAGE_ACTIVATE_SERVICE, serial, connection);
+      goto out;
+    }
+
+  _dbus_verbose ("Received %s on %p\n",
+                 dbus_message_get_name (message), connection);
+
+  if (dbus_message_get_is_error (message))
+    {
+      if (!dbus_message_sender_is (message, DBUS_SERVICE_DBUS))
+        {
+          _dbus_warn ("Message has wrong sender %s\n",
+                      dbus_message_get_sender (message) ?
+                      dbus_message_get_sender (message) : "(none)");
+          goto out;
+        }
+      
+      if (dbus_message_name_is (message,
+                                DBUS_ERROR_NO_MEMORY))
+        {
+          ; /* good, this is a valid response */
+        }
+      else if (dbus_message_name_is (message,
+                                     DBUS_ERROR_ACTIVATE_SERVICE_NOT_FOUND))
+        {
+          ; /* good, this is expected also */
+        }
+      else
+        {
+          _dbus_warn ("Did not expect error %s\n",
+                      dbus_message_get_name (message));
+          goto out;
+        }
+    }
+  else
+    {
+      _dbus_warn ("Did not expect to successfully activate %s\n",
+                  EXISTENT_SERVICE_NAME);
+      goto out;
+    }
+
+  retval = TRUE;
+  
+ out:
+  if (message)
+    dbus_message_unref (message);
+  
+  return retval;
+}
+
 typedef struct
 {
   Check1Func func;
@@ -1153,6 +1263,11 @@ bus_dispatch_test (const DBusString *test_data_dir)
   if (!check_hello_message (context, baz))
     _dbus_assert_not_reached ("hello message failed");
 
+#if 0
+  check2_try_iterations (context, foo, "existent_service_activation",
+                         check_existent_service_activation);
+#endif
+  
   check2_try_iterations (context, foo, "nonexistent_service_activation",
                          check_nonexistent_service_activation);
 
index 93096dc..a237def 100644 (file)
 #include <dbus/dbus-list.h>
 #include <dbus/dbus-sysdeps.h>
 
-static DBusList *callbacks = NULL;
-static int callback_list_serial = 0;
-static int watch_count = 0;
-static int timeout_count = 0;
-static dbus_bool_t exited = FALSE;
+struct BusLoop
+{
+  int refcount;
+  DBusList *callbacks;
+  int callback_list_serial;
+  int watch_count;
+  int timeout_count;
+  int depth; /**< number of recursive runs */
+};
 
 typedef enum
 {
@@ -121,20 +125,21 @@ callback_free (Callback *cb)
 }
 
 static dbus_bool_t
-add_callback (Callback *cb)
+add_callback (BusLoop  *loop,
+              Callback *cb)
 {
-  if (!_dbus_list_append (&callbacks, cb))
+  if (!_dbus_list_append (&loop->callbacks, cb))
     return FALSE;
 
-  callback_list_serial += 1;
+  loop->callback_list_serial += 1;
 
   switch (cb->type)
     {
     case CALLBACK_WATCH:
-      watch_count += 1;
+      loop->watch_count += 1;
       break;
     case CALLBACK_TIMEOUT:
-      timeout_count += 1;
+      loop->timeout_count += 1;
       break;
     }
   
@@ -142,27 +147,66 @@ add_callback (Callback *cb)
 }
 
 static void
-remove_callback (DBusList *link)
+remove_callback (BusLoop  *loop,
+                 DBusList *link)
 {
   Callback *cb = link->data;
   
   switch (cb->type)
     {
     case CALLBACK_WATCH:
-      watch_count -= 1;
+      loop->watch_count -= 1;
       break;
     case CALLBACK_TIMEOUT:
-      timeout_count -= 1;
+      loop->timeout_count -= 1;
       break;
     }
   
   callback_free (cb);
-  _dbus_list_remove_link (&callbacks, link);
-  callback_list_serial += 1;
+  _dbus_list_remove_link (&loop->callbacks, link);
+  loop->callback_list_serial += 1;
+}
+
+BusLoop*
+bus_loop_new (void)
+{
+  BusLoop *loop;
+
+  loop = dbus_new0 (BusLoop, 1);
+  if (loop == NULL)
+    return NULL;
+
+  loop->refcount = 1;
+  
+  return loop;
+}
+
+void
+bus_loop_ref (BusLoop *loop)
+{
+  _dbus_assert (loop != NULL);
+  _dbus_assert (loop->refcount > 0);
+
+  loop->refcount += 1;
+}
+
+void
+bus_loop_unref (BusLoop *loop)
+{
+  _dbus_assert (loop != NULL);
+  _dbus_assert (loop->refcount > 0);
+
+  loop->refcount -= 1;
+  if (loop->refcount == 0)
+    {
+      
+      dbus_free (loop);
+    }
 }
 
 dbus_bool_t
-bus_loop_add_watch (DBusWatch        *watch,
+bus_loop_add_watch (BusLoop          *loop,
+                    DBusWatch        *watch,
                     BusWatchFunction  function,
                     void             *data,
                     DBusFreeFunction  free_data_func)
@@ -173,7 +217,7 @@ bus_loop_add_watch (DBusWatch        *watch,
   if (wcb == NULL)
     return FALSE;
 
-  if (!add_callback ((Callback*) wcb))
+  if (!add_callback (loop, (Callback*) wcb))
     {
       wcb->callback.free_data_func = NULL; /* don't want to have this side effect */
       callback_free ((Callback*) wcb);
@@ -184,16 +228,17 @@ bus_loop_add_watch (DBusWatch        *watch,
 }
 
 void
-bus_loop_remove_watch (DBusWatch        *watch,
+bus_loop_remove_watch (BusLoop          *loop,
+                       DBusWatch        *watch,
                        BusWatchFunction  function,
                        void             *data)
 {
   DBusList *link;
   
-  link = _dbus_list_get_first_link (&callbacks);
+  link = _dbus_list_get_first_link (&loop->callbacks);
   while (link != NULL)
     {
-      DBusList *next = _dbus_list_get_next_link (&callbacks, link);
+      DBusList *next = _dbus_list_get_next_link (&loop->callbacks, link);
       Callback *this = link->data;
 
       if (this->type == CALLBACK_WATCH &&
@@ -201,7 +246,7 @@ bus_loop_remove_watch (DBusWatch        *watch,
           this->data == data &&
           WATCH_CALLBACK (this)->function == function)
         {
-          remove_callback (link);
+          remove_callback (loop, link);
           
           return;
         }
@@ -214,7 +259,8 @@ bus_loop_remove_watch (DBusWatch        *watch,
 }
 
 dbus_bool_t
-bus_loop_add_timeout (DBusTimeout        *timeout,
+bus_loop_add_timeout (BusLoop            *loop,
+                      DBusTimeout        *timeout,
                       BusTimeoutFunction  function,
                       void               *data,
                       DBusFreeFunction    free_data_func)
@@ -225,7 +271,7 @@ bus_loop_add_timeout (DBusTimeout        *timeout,
   if (tcb == NULL)
     return FALSE;
 
-  if (!add_callback ((Callback*) tcb))
+  if (!add_callback (loop, (Callback*) tcb))
     {
       tcb->callback.free_data_func = NULL; /* don't want to have this side effect */
       callback_free ((Callback*) tcb);
@@ -236,16 +282,17 @@ bus_loop_add_timeout (DBusTimeout        *timeout,
 }
 
 void
-bus_loop_remove_timeout (DBusTimeout        *timeout,
+bus_loop_remove_timeout (BusLoop            *loop,
+                         DBusTimeout        *timeout,
                          BusTimeoutFunction  function,
                          void               *data)
 {
   DBusList *link;
   
-  link = _dbus_list_get_first_link (&callbacks);
+  link = _dbus_list_get_first_link (&loop->callbacks);
   while (link != NULL)
     {
-      DBusList *next = _dbus_list_get_next_link (&callbacks, link);
+      DBusList *next = _dbus_list_get_next_link (&loop->callbacks, link);
       Callback *this = link->data;
 
       if (this->type == CALLBACK_TIMEOUT &&
@@ -253,7 +300,7 @@ bus_loop_remove_timeout (DBusTimeout        *timeout,
           this->data == data &&
           TIMEOUT_CALLBACK (this)->function == function)
         {
-          remove_callback (link);
+          remove_callback (loop, link);
           
           return;
         }
@@ -270,7 +317,8 @@ bus_loop_remove_timeout (DBusTimeout        *timeout,
  */
 
 dbus_bool_t
-bus_loop_iterate (dbus_bool_t block)
+bus_loop_iterate (BusLoop     *loop,
+                  dbus_bool_t  block)
 {
   dbus_bool_t retval;
   DBusPollFD *fds;
@@ -282,30 +330,32 @@ bus_loop_iterate (dbus_bool_t block)
   int initial_serial;
   long timeout;
   dbus_bool_t oom_watch_pending;
+  int orig_depth;
   
   retval = FALSE;
       
   fds = NULL;
   watches_for_fds = NULL;
   oom_watch_pending = FALSE;
-
+  orig_depth = loop->depth;
+  
 #if 0
   _dbus_verbose (" iterate %d timeouts %d watches\n",
-                 timeout_count, watch_count);
+                 loop->timeout_count, loop->watch_count);
 #endif
   
-  if (callbacks == NULL)
+  if (loop->callbacks == NULL)
     {
-      bus_loop_quit ();
+      bus_loop_quit (loop);
       goto next_iteration;
     }
 
   /* count enabled watches */
   n_fds = 0;
-  link = _dbus_list_get_first_link (&callbacks);
+  link = _dbus_list_get_first_link (&loop->callbacks);
   while (link != NULL)
     {
-      DBusList *next = _dbus_list_get_next_link (&callbacks, link);
+      DBusList *next = _dbus_list_get_next_link (&loop->callbacks, link);
       Callback *cb = link->data;
       if (cb->type == CALLBACK_WATCH)
         {
@@ -337,10 +387,10 @@ bus_loop_iterate (dbus_bool_t block)
         }
       
       i = 0;
-      link = _dbus_list_get_first_link (&callbacks);
+      link = _dbus_list_get_first_link (&loop->callbacks);
       while (link != NULL)
         {
-          DBusList *next = _dbus_list_get_next_link (&callbacks, link);
+          DBusList *next = _dbus_list_get_next_link (&loop->callbacks, link);
           Callback *cb = link->data;
           if (cb->type == CALLBACK_WATCH)
             {
@@ -378,7 +428,7 @@ bus_loop_iterate (dbus_bool_t block)
     }
 
   timeout = -1;
-  if (timeout_count > 0)
+  if (loop->timeout_count > 0)
     {
       unsigned long tv_sec;
       unsigned long tv_usec;
@@ -387,10 +437,10 @@ bus_loop_iterate (dbus_bool_t block)
       
       _dbus_get_current_time (&tv_sec, &tv_usec);
           
-      link = _dbus_list_get_first_link (&callbacks);
+      link = _dbus_list_get_first_link (&loop->callbacks);
       while (link != NULL)
         {
-          DBusList *next = _dbus_list_get_next_link (&callbacks, link);
+          DBusList *next = _dbus_list_get_next_link (&loop->callbacks, link);
           Callback *cb = link->data;
 
           if (cb->type == CALLBACK_TIMEOUT &&
@@ -446,9 +496,9 @@ bus_loop_iterate (dbus_bool_t block)
   
   n_ready = _dbus_poll (fds, n_fds, timeout);
 
-  initial_serial = callback_list_serial;
+  initial_serial = loop->callback_list_serial;
 
-  if (timeout_count > 0)
+  if (loop->timeout_count > 0)
     {
       unsigned long tv_sec;
       unsigned long tv_usec;
@@ -456,16 +506,16 @@ bus_loop_iterate (dbus_bool_t block)
       _dbus_get_current_time (&tv_sec, &tv_usec);
 
       /* It'd be nice to avoid this O(n) thingy here */
-      link = _dbus_list_get_first_link (&callbacks);
+      link = _dbus_list_get_first_link (&loop->callbacks);
       while (link != NULL)
         {
-          DBusList *next = _dbus_list_get_next_link (&callbacks, link);
+          DBusList *next = _dbus_list_get_next_link (&loop->callbacks, link);
           Callback *cb = link->data;
 
-          if (initial_serial != callback_list_serial)
+          if (initial_serial != loop->callback_list_serial)
             goto next_iteration;
 
-          if (exited)
+          if (loop->depth != orig_depth)
             goto next_iteration;
               
           if (cb->type == CALLBACK_TIMEOUT &&
@@ -528,10 +578,10 @@ bus_loop_iterate (dbus_bool_t block)
            * approach could result in starving watches
            * toward the end of the list.
            */
-          if (initial_serial != callback_list_serial)
+          if (initial_serial != loop->callback_list_serial)
             goto next_iteration;
 
-          if (exited)
+          if (loop->depth != orig_depth)
             goto next_iteration;
 
           if (fds[i].revents != 0)
@@ -578,16 +628,26 @@ bus_loop_iterate (dbus_bool_t block)
   return retval;
 }
 
-
 void
-bus_loop_run (void)
+bus_loop_run (BusLoop *loop)
 {
-  while (!exited)
-    bus_loop_iterate (TRUE);
+  int our_exit_depth;
+
+  bus_loop_ref (loop);
+  
+  our_exit_depth = loop->depth;
+  loop->depth += 1;
+  
+  while (loop->depth != our_exit_depth)
+    bus_loop_iterate (loop, TRUE);
+
+  bus_loop_unref (loop);
 }
 
 void
-bus_loop_quit (void)
+bus_loop_quit (BusLoop *loop)
 {
-  exited = TRUE;
+  _dbus_assert (loop->depth > 0);
+  
+  loop->depth -= 1;
 }
index b217a77..19b3bcd 100644 (file)
 
 #include <dbus/dbus.h>
 
+typedef struct BusLoop BusLoop;
+
 typedef dbus_bool_t (* BusWatchFunction)   (DBusWatch     *watch,
                                             unsigned int   condition,
                                             void          *data);
 typedef void        (* BusTimeoutFunction) (DBusTimeout   *timeout,
                                             void          *data);
 
-dbus_bool_t bus_loop_add_watch      (DBusWatch          *watch,
+
+BusLoop*    bus_loop_new            (void);
+void        bus_loop_ref            (BusLoop            *loop);
+void        bus_loop_unref          (BusLoop            *loop);
+dbus_bool_t bus_loop_add_watch      (BusLoop            *loop,
+                                     DBusWatch          *watch,
                                      BusWatchFunction    function,
                                      void               *data,
                                      DBusFreeFunction    free_data_func);
-void        bus_loop_remove_watch   (DBusWatch          *watch,
+void        bus_loop_remove_watch   (BusLoop            *loop,
+                                     DBusWatch          *watch,
                                      BusWatchFunction    function,
                                      void               *data);
-dbus_bool_t bus_loop_add_timeout    (DBusTimeout        *timeout,
+dbus_bool_t bus_loop_add_timeout    (BusLoop            *loop,
+                                     DBusTimeout        *timeout,
                                      BusTimeoutFunction  function,
                                      void               *data,
                                      DBusFreeFunction    free_data_func);
-void        bus_loop_remove_timeout (DBusTimeout        *timeout,
+void        bus_loop_remove_timeout (BusLoop            *loop,
+                                     DBusTimeout        *timeout,
                                      BusTimeoutFunction  function,
                                      void               *data);
-void        bus_loop_run            (void);
-void        bus_loop_quit           (void);
-dbus_bool_t bus_loop_iterate        (dbus_bool_t         block);
+void        bus_loop_run            (BusLoop            *loop);
+void        bus_loop_quit           (BusLoop            *loop);
+dbus_bool_t bus_loop_iterate        (BusLoop            *loop,
+                                     dbus_bool_t         block);
+
 
 #endif /* BUS_LOOP_H */
index fcde349..099219c 100644 (file)
@@ -143,7 +143,7 @@ main (int argc, char **argv)
     }
   
   _dbus_verbose ("We are on D-Bus...\n");
-  bus_loop_run ();
+  bus_loop_run (bus_context_get_loop (context));
   
   bus_context_shutdown (context);
   bus_context_unref (context);
index d669708..00a522c 100644 (file)
  * are different from the real handlers in connection.c
  */
 static DBusList *clients = NULL;
+static BusLoop *client_loop = NULL;
 
 static dbus_bool_t
 client_watch_callback (DBusWatch     *watch,
-                           unsigned int   condition,
-                           void          *data)
+                       unsigned int   condition,
+                       void          *data)
 {
   DBusConnection *connection = data;
   dbus_bool_t retval;
@@ -54,22 +55,28 @@ client_watch_callback (DBusWatch     *watch,
 
 static dbus_bool_t
 add_client_watch (DBusWatch      *watch,
-                      DBusConnection *connection)
+                  void           *data)
 {
-  return bus_loop_add_watch (watch, client_watch_callback, connection,
+  DBusConnection *connection = data;
+  
+  return bus_loop_add_watch (client_loop,
+                             watch, client_watch_callback, connection,
                              NULL);
 }
 
 static void
 remove_client_watch (DBusWatch      *watch,
-                         DBusConnection *connection)
+                     void           *data)
 {
-  bus_loop_remove_watch (watch, client_watch_callback, connection);
+  DBusConnection *connection = data;
+  
+  bus_loop_remove_watch (client_loop,
+                         watch, client_watch_callback, connection);
 }
 
 static void
 client_timeout_callback (DBusTimeout   *timeout,
-                             void          *data)
+                         void          *data)
 {
   DBusConnection *connection = data;
 
@@ -83,16 +90,20 @@ client_timeout_callback (DBusTimeout   *timeout,
 
 static dbus_bool_t
 add_client_timeout (DBusTimeout    *timeout,
-                        DBusConnection *connection)
+                    void           *data)
 {
-  return bus_loop_add_timeout (timeout, client_timeout_callback, connection, NULL);
+  DBusConnection *connection = data;
+  
+  return bus_loop_add_timeout (client_loop, timeout, client_timeout_callback, connection, NULL);
 }
 
 static void
 remove_client_timeout (DBusTimeout    *timeout,
-                           DBusConnection *connection)
+                       void           *data)
 {
-  bus_loop_remove_timeout (timeout, client_timeout_callback, connection);
+  DBusConnection *connection = data;
+  
+  bus_loop_remove_timeout (client_loop, timeout, client_timeout_callback, connection);
 }
 
 static DBusHandlerResult
@@ -105,9 +116,15 @@ client_disconnect_handler (DBusMessageHandler *handler,
                  connection);
   
   _dbus_list_remove (&clients, connection);
-  
+
   dbus_connection_unref (connection);
   
+  if (clients == NULL)
+    {
+      bus_loop_unref (client_loop);
+      client_loop = NULL;
+    }
+  
   return DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
 }
 
@@ -179,18 +196,25 @@ bus_setup_debug_client (DBusConnection *connection)
     }
 
   retval = FALSE;
+
+  if (client_loop == NULL)
+    {
+      client_loop = bus_loop_new ();
+      if (client_loop == NULL)
+        goto out;
+    }
   
   if (!dbus_connection_set_watch_functions (connection,
-                                            (DBusAddWatchFunction) add_client_watch,
-                                            (DBusRemoveWatchFunction) remove_client_watch,
+                                            add_client_watch,
+                                            remove_client_watch,
                                             NULL,
                                             connection,
                                             NULL))
     goto out;
       
   if (!dbus_connection_set_timeout_functions (connection,
-                                              (DBusAddTimeoutFunction) add_client_timeout,
-                                              (DBusRemoveTimeoutFunction) remove_client_timeout,
+                                              add_client_timeout,
+                                              remove_client_timeout,
                                               NULL,
                                               connection, NULL))
     goto out;
@@ -223,6 +247,12 @@ bus_setup_debug_client (DBusConnection *connection)
                                              NULL, NULL, NULL, NULL, NULL);
 
       _dbus_list_remove_last (&clients, connection);
+
+      if (clients == NULL)
+        {
+          bus_loop_unref (client_loop);
+          client_loop = NULL;
+        }
     }
       
   return retval;
@@ -268,25 +298,45 @@ bus_test_client_listed (DBusConnection *connection)
 }
 
 void
-bus_test_flush_bus (BusContext *context)
+bus_test_run_clients_loop (void)
 {
-  /* This is race condition city, obviously. since we're all in one
-   * process we can't block, we just have to wait for data we put in
-   * one end of the debug pipe to come out the other end...
-   * a more robust setup would be good. Blocking on the other
-   * end of pipes we've pushed data into or something.
-   * A simple hack might be to just make the debug server always
-   * poll for read on the other end of the pipe after writing.
-   */
-  while (bus_loop_iterate (FALSE))
+  if (client_loop == NULL)
+    return;
+  
+  /* Do one blocking wait, since we're expecting data */
+  bus_loop_iterate (client_loop, TRUE);
+
+  /* Then mop everything up */
+  while (bus_loop_iterate (client_loop, FALSE))
     ;
-#if 0
-  _dbus_sleep_milliseconds (15);
-#endif
-  while (bus_loop_iterate (FALSE))
+}
+
+void
+bus_test_run_bus_loop (BusContext *context)
+{
+  /* Do one blocking wait, since we're expecting data */
+  bus_loop_iterate (bus_context_get_loop (context), TRUE);
+
+  /* Then mop everything up */
+  while (bus_loop_iterate (bus_context_get_loop (context), FALSE))
     ;
 }
 
+void
+bus_test_run_everything (BusContext *context)
+{
+  int i;
+
+  i = 0;
+  while (i < 2)
+    {
+      while (bus_loop_iterate (bus_context_get_loop (context), FALSE) ||
+             (client_loop == NULL || bus_loop_iterate (client_loop, FALSE)))
+        ;
+      ++i;
+    }
+}
+
 BusContext*
 bus_context_new_test (const DBusString *test_data_dir,
                       const char       *filename)
index d8ab67b..5606bb9 100644 (file)
 #include <dbus/dbus-string.h>
 #include "connection.h"
 
-dbus_bool_t bus_dispatch_test        (const DBusString             *test_data_dir);
-dbus_bool_t bus_policy_test          (const DBusString             *test_data_dir);
-dbus_bool_t bus_config_parser_test   (const DBusString             *test_data_dir);
-dbus_bool_t bus_setup_debug_client   (DBusConnection               *connection);
-void        bus_test_clients_foreach (BusConnectionForeachFunction  function,
-                                      void                         *data);
-dbus_bool_t bus_test_client_listed   (DBusConnection               *connection);
-void        bus_test_flush_bus       (BusContext                   *context);
-
-BusContext* bus_context_new_test     (const DBusString             *test_data_dir,
-                                      const char                   *filename);
+dbus_bool_t bus_dispatch_test         (const DBusString             *test_data_dir);
+dbus_bool_t bus_policy_test           (const DBusString             *test_data_dir);
+dbus_bool_t bus_config_parser_test    (const DBusString             *test_data_dir);
+dbus_bool_t bus_setup_debug_client    (DBusConnection               *connection);
+void        bus_test_clients_foreach  (BusConnectionForeachFunction  function,
+                                       void                         *data);
+dbus_bool_t bus_test_client_listed    (DBusConnection               *connection);
+void        bus_test_run_bus_loop     (BusContext                   *context);
+void        bus_test_run_clients_loop (void);
+void        bus_test_run_everything   (BusContext                   *context);
+BusContext* bus_context_new_test      (const DBusString             *test_data_dir,
+                                       const char                   *filename);
+
 
 #endif
 
index f6c539d..c4e3e83 100644 (file)
--- a/doc/TODO
+++ b/doc/TODO
@@ -59,3 +59,9 @@
    to return an error that automatically gets turned into a message; most likely 
    some basic spec'ing out of the GLib/Qt level stubs/skels stuff will be 
    needed to understand the right approach.
+
+ - sync up DBusWatch and DBusTimeout so that handle_watch() is a method on DBusWatch 
+   similar to the way timeouts work
+
+ - there are various bits of code to manage ref/unref of data slots, that should 
+   be merged into a generic facility