2003-03-16 Anders Carlsson <andersca@codefactory.se>
authorAnders Carlsson <andersca@codefactory.se>
Sun, 16 Mar 2003 22:25:18 +0000 (22:25 +0000)
committerAnders Carlsson <andersca@codefactory.se>
Sun, 16 Mar 2003 22:25:18 +0000 (22:25 +0000)
* bus/activation.c: (bus_pending_activation_entry_free),
(bus_pending_activation_free), (bus_activation_new),
(bus_activation_unref), (bus_activation_service_created),
(bus_activation_activate_service):
* bus/activation.h:
* bus/bus.c: (bus_context_new):
* bus/desktop-file.c: (new_section):
* bus/driver.c: (bus_driver_send_service_deleted),
(bus_driver_handle_activate_service):
* bus/services.c: (bus_registry_new), (bus_registry_ensure):
* bus/services.h:
* dbus/dbus-connection.c:
(dbus_connection_send_with_reply_and_block):
* dbus/dbus-message.c: (dbus_message_append_args_valist):
* dbus/dbus-protocol.h:
Make activation work better. Now pending activations will be queued
and the daemon won't try to activate services that are already registered.

ChangeLog
bus/activation.c
bus/activation.h
bus/bus.c
bus/desktop-file.c
bus/driver.c
bus/services.c
bus/services.h
dbus/dbus-connection.c
dbus/dbus-message.c
dbus/dbus-protocol.h

index 76310fc..7740ee1 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,23 @@
+2003-03-16  Anders Carlsson  <andersca@codefactory.se>
+
+       * bus/activation.c: (bus_pending_activation_entry_free),
+       (bus_pending_activation_free), (bus_activation_new),
+       (bus_activation_unref), (bus_activation_service_created),
+       (bus_activation_activate_service):
+       * bus/activation.h:
+       * bus/bus.c: (bus_context_new):
+       * bus/desktop-file.c: (new_section):
+       * bus/driver.c: (bus_driver_send_service_deleted),
+       (bus_driver_handle_activate_service):
+       * bus/services.c: (bus_registry_new), (bus_registry_ensure):
+       * bus/services.h:
+       * dbus/dbus-connection.c:
+       (dbus_connection_send_with_reply_and_block):
+       * dbus/dbus-message.c: (dbus_message_append_args_valist):
+       * dbus/dbus-protocol.h:
+       Make activation work better. Now pending activations will be queued
+       and the daemon won't try to activate services that are already registered.
+       
 2003-03-16  Havoc Pennington  <hp@pobox.com>
 
        * dbus/dbus-bus.c (ensure_bus_data): handle failure to set
index ba130ed..c7d08ba 100644 (file)
  */
 #include "activation.h"
 #include "desktop-file.h"
+#include "services.h"
 #include "utils.h"
 #include <dbus/dbus-internals.h>
 #include <dbus/dbus-hash.h>
+#include <dbus/dbus-list.h>
 #include <sys/types.h>
 #include <dirent.h>
 #include <errno.h>
@@ -37,7 +39,9 @@ struct BusActivation
 {
   int refcount;
   DBusHashTable *entries;
+  DBusHashTable *pending_activations;
   char *server_address;
+  BusContext *context;
 };
 
 typedef struct
@@ -46,6 +50,57 @@ typedef struct
   char *exec;
 } BusActivationEntry;
 
+typedef struct BusPendingActivationEntry BusPendingActivationEntry;
+
+struct BusPendingActivationEntry
+{
+  DBusMessage *activation_message;
+  DBusConnection *connection;
+};
+
+typedef struct
+{
+  char *service_name;
+  DBusList *entries;
+} BusPendingActivation;
+
+static void
+bus_pending_activation_entry_free (BusPendingActivationEntry *entry)
+{
+  if (entry->activation_message)
+    dbus_message_unref (entry->activation_message);
+  
+  if (entry->connection)
+    dbus_connection_unref (entry->connection);
+
+  dbus_free (entry);
+}
+
+static void
+bus_pending_activation_free (BusPendingActivation *activation)
+{
+  DBusList *link;
+  
+  if (!activation)
+    return;
+
+  dbus_free (activation->service_name);
+
+  link = _dbus_list_get_first_link (&activation->entries);
+
+  while (link != NULL)
+    {
+      BusPendingActivationEntry *entry = link->data;
+
+      bus_pending_activation_entry_free (entry);
+
+      link = _dbus_list_get_next_link (&activation->entries, link);
+    }
+  _dbus_list_clear (&activation->entries);
+  
+  dbus_free (activation);
+}
+
 static void
 bus_activation_entry_free (BusActivationEntry *entry)
 {
@@ -264,7 +319,8 @@ load_directory (BusActivation *activation,
 }
 
 BusActivation*
-bus_activation_new (const char  *address,
+bus_activation_new (BusContext  *context,
+                   const char  *address,
                     const char **directories,
                     DBusError   *error)
 {
@@ -279,6 +335,7 @@ bus_activation_new (const char  *address,
     }
   
   activation->refcount = 1;
+  activation->context = context;
   
   /* FIXME: We should split up the server addresses. */
   activation->server_address = _dbus_strdup (address);
@@ -296,6 +353,15 @@ bus_activation_new (const char  *address,
       goto failed;
     }
 
+  activation->pending_activations = _dbus_hash_table_new (DBUS_HASH_STRING, NULL,
+                                                         (DBusFreeFunction)bus_pending_activation_free);
+
+  if (activation->pending_activations == NULL)
+    {
+      BUS_SET_OOM (error);
+      goto failed;
+    }
+  
   /* Load service files */
   i = 0;
   while (directories[i] != NULL)
@@ -332,6 +398,8 @@ bus_activation_unref (BusActivation *activation)
       dbus_free (activation->server_address);
       if (activation->entries)
         _dbus_hash_table_unref (activation->entries);
+      if (activation->pending_activations)
+       _dbus_hash_table_unref (activation->pending_activations);
       dbus_free (activation);
     }
 }
@@ -349,12 +417,81 @@ child_setup (void *data)
 }
 
 dbus_bool_t
-bus_activation_activate_service (BusActivation *activation,
-                                 const char    *service_name,
-                                DBusError     *error)
+bus_activation_service_created (BusActivation *activation,
+                               const char    *service_name,
+                               DBusError     *error)
+{
+  BusPendingActivation *pending_activation;
+  DBusMessage *message;
+  DBusList *link;
+  
+  /* Check if it's a pending activation */
+  pending_activation = _dbus_hash_table_lookup_string (activation->pending_activations, service_name);
+
+  if (!pending_activation)
+    return TRUE;
+
+  link = _dbus_list_get_first_link (&pending_activation->entries);
+  while (link != NULL)
+    {
+      BusPendingActivationEntry *entry = link->data;
+      DBusList *next = _dbus_list_get_next_link (&pending_activation->entries, link);
+      
+      if (dbus_connection_get_is_connected (entry->connection))
+       {
+         message = dbus_message_new_reply (entry->activation_message);
+         if (!message)
+           {
+             BUS_SET_OOM (error);
+             goto error;
+           }
+
+         if (!dbus_message_append_args (message,
+                                        DBUS_TYPE_UINT32, DBUS_ACTIVATION_REPLY_ACTIVATED,
+                                        0))
+           {
+             dbus_message_unref (message);
+             BUS_SET_OOM (error);
+             goto error;
+           }
+
+         if (!dbus_connection_send (entry->connection, message, NULL))
+           {
+             dbus_message_unref (message);
+             BUS_SET_OOM (error);
+             goto error;
+           }
+       }
+
+      bus_pending_activation_entry_free (entry);
+      
+      _dbus_list_remove_link (&pending_activation->entries, link);      
+      link = next;
+    }
+  
+  _dbus_hash_table_remove_string (activation->pending_activations, service_name);
+
+  return TRUE;
+
+ error:
+  _dbus_hash_table_remove_string (activation->pending_activations, service_name);
+  return FALSE;
+}
+
+dbus_bool_t
+bus_activation_activate_service (BusActivation  *activation,
+                                DBusConnection *connection,
+                                DBusMessage    *activation_message,
+                                 const char     *service_name,
+                                DBusError      *error)
 {
   BusActivationEntry *entry;
+  BusPendingActivation *pending_activation;
+  BusPendingActivationEntry *pending_activation_entry;
+  DBusMessage *message;
+  DBusString service_str;
   char *argv[2];
+  dbus_bool_t retval;
   
   entry = _dbus_hash_table_lookup_string (activation->entries, service_name);
 
@@ -366,6 +503,94 @@ bus_activation_activate_service (BusActivation *activation,
       return FALSE;
     }
 
+  /* Check if the service is active */
+  _dbus_string_init_const (&service_str, service_name);
+  if (bus_registry_lookup (bus_context_get_registry (activation->context), &service_str) != NULL)
+    {
+      message = dbus_message_new_reply (activation_message);
+
+      if (!message)
+       {
+         BUS_SET_OOM (error);
+         return FALSE;
+       }
+
+      if (!dbus_message_append_args (message,
+                                    DBUS_TYPE_UINT32, DBUS_ACTIVATION_REPLY_ALREADY_ACTIVE, 
+                                    0))
+       {
+         BUS_SET_OOM (error);
+         dbus_message_unref (message);
+         return FALSE;
+       }
+
+      retval = dbus_connection_send (connection, message, NULL);
+      dbus_message_unref (message);
+      if (!retval)
+       BUS_SET_OOM (error);
+
+      return retval;
+    }
+
+  pending_activation_entry = dbus_new0 (BusPendingActivationEntry, 1);
+  if (!pending_activation_entry)
+    {
+      BUS_SET_OOM (error);
+      return FALSE;
+    }
+
+  pending_activation_entry->activation_message = activation_message;
+  dbus_message_ref (activation_message);
+  pending_activation_entry->connection = connection;
+  dbus_connection_ref (connection);
+  
+  /* Check if the service is being activated */
+  pending_activation = _dbus_hash_table_lookup_string (activation->pending_activations, service_name);
+  if (pending_activation)
+    {
+      if (!_dbus_list_append (&pending_activation->entries, entry))
+       {
+         BUS_SET_OOM (error);
+         bus_pending_activation_entry_free (pending_activation_entry);
+
+         return FALSE;
+       }
+    }
+  else
+    {
+      pending_activation = dbus_new0 (BusPendingActivation, 1);
+      if (!pending_activation)
+       {
+         BUS_SET_OOM (error);
+         bus_pending_activation_entry_free (pending_activation_entry);   
+         return FALSE;
+       }
+      pending_activation->service_name = _dbus_strdup (service_name);
+      if (!pending_activation->service_name)
+       {
+         BUS_SET_OOM (error);
+         bus_pending_activation_free (pending_activation);
+         bus_pending_activation_entry_free (pending_activation_entry);   
+         return FALSE;
+       }
+
+      if (!_dbus_list_append (&pending_activation->entries, entry))
+       {
+         BUS_SET_OOM (error);
+         bus_pending_activation_free (pending_activation);
+         bus_pending_activation_entry_free (pending_activation_entry);   
+         return FALSE;
+       }
+      
+      if (!_dbus_hash_table_insert_string (activation->pending_activations,
+                                          pending_activation->service_name, pending_activation))
+       {
+         BUS_SET_OOM (error);
+         bus_pending_activation_free (pending_activation);
+         return FALSE;
+       }
+    }
+  
   /* FIXME we need to support a full command line, not just a single
    * argv[0]
    */
@@ -377,7 +602,11 @@ bus_activation_activate_service (BusActivation *activation,
   if (!_dbus_spawn_async (argv,
                          child_setup, activation, 
                          error))
-    return FALSE;
-
+    {
+      _dbus_hash_table_remove_string (activation->pending_activations,
+                                     pending_activation->service_name);
+      return FALSE;
+    }
+  
   return TRUE;
 }
index 4e363c9..1fd416e 100644 (file)
 #include <dbus/dbus.h>
 #include "bus.h"
 
-BusActivation* bus_activation_new              (const char     *address,
-                                                const char    **paths,
-                                                DBusError      *error);
+BusActivation* bus_activation_new              (BusContext     *context,
+                                               const char     *address,
+                                               const char    **paths,
+                                               DBusError      *error);
 void           bus_activation_ref              (BusActivation  *activation);
 void           bus_activation_unref            (BusActivation  *activation);
 dbus_bool_t    bus_activation_activate_service (BusActivation  *activation,
-                                                const char     *service_name,
-                                                DBusError      *error);
-
-
+                                               DBusConnection *connection, 
+                                               DBusMessage    *activation_message,
+                                               const char     *service_name,
+                                               DBusError      *error);
+dbus_bool_t    bus_activation_service_created  (BusActivation  *activation,
+                                               const char     *service_name,
+                                               DBusError      *error);
 
 #endif /* BUS_ACTIVATION_H */
index 4319e5f..589dda1 100644 (file)
--- a/bus/bus.c
+++ b/bus/bus.c
@@ -141,7 +141,7 @@ bus_context_new (const char  *address,
       goto failed;
     }
 
-  context->activation = bus_activation_new (address, service_dirs,
+  context->activation = bus_activation_new (context, address, service_dirs,
                                             error);
   if (context->activation == NULL)
     {
@@ -156,7 +156,7 @@ bus_context_new (const char  *address,
       goto failed;
     }
 
-  context->registry = bus_registry_new ();
+  context->registry = bus_registry_new (context);
   if (context->registry == NULL)
     {
       BUS_SET_OOM (error);
index 65a0d76..f45a997 100644 (file)
@@ -272,8 +272,8 @@ new_section (BusDesktopFile *desktop_file,
   name_copy = _dbus_strdup (name);
   if (name_copy == NULL)
     return NULL;
-  
-  n = desktop_file->n_sections + 1;
+
+  n = desktop_file->n_sections;
   desktop_file->sections[n].section_name = name_copy;
 
   desktop_file->sections[n].n_lines = 0;
@@ -287,7 +287,7 @@ new_section (BusDesktopFile *desktop_file,
       return NULL;
     }
 
-  desktop_file->n_sections = n;
+  desktop_file->n_sections += 1;
   
   return &desktop_file->sections[n];  
 }
index 09ec18a..98085fc 100644 (file)
@@ -45,7 +45,7 @@ bus_driver_send_service_deleted (const char     *service_name,
   dbus_bool_t retval;
   
   _dbus_verbose ("sending service deleted: %s\n", service_name);
-  
+
   message = dbus_message_new (DBUS_SERVICE_BROADCAST,
                               DBUS_MESSAGE_SERVICE_DELETED);
   if (message == NULL)
@@ -625,7 +625,7 @@ bus_driver_handle_activate_service (DBusConnection *connection,
 
   retval = FALSE;
 
-  if (!bus_activation_activate_service (activation, name, error))
+  if (!bus_activation_activate_service (activation, connection, message, name, error))
     goto out;
 
   retval = TRUE;
index 92f6cdf..821cb4a 100644 (file)
@@ -29,6 +29,7 @@
 #include "services.h"
 #include "connection.h"
 #include "utils.h"
+#include "activation.h"
 
 struct BusService
 {
@@ -42,13 +43,15 @@ struct BusService
 struct BusRegistry
 {
   int refcount;
+
+  BusContext *context;
   
   DBusHashTable *service_hash;
   DBusMemPool   *service_pool;
 };
 
 BusRegistry*
-bus_registry_new (void)
+bus_registry_new (BusContext *context)
 {
   BusRegistry *registry;
 
@@ -57,7 +60,8 @@ bus_registry_new (void)
     return NULL;
 
   registry->refcount = 1;
-
+  registry->context = context;
+  
   registry->service_hash = _dbus_hash_table_new (DBUS_HASH_STRING,
                                                  NULL, NULL);
   if (registry->service_hash == NULL)
@@ -158,6 +162,14 @@ bus_registry_ensure (BusRegistry               *registry,
       return NULL;
     }
 
+  if (!bus_activation_service_created (bus_context_get_activation (registry->context),
+                                      service->name, error))
+    {
+      dbus_free (service->name);
+      _dbus_mem_pool_dealloc (registry->service_pool, service);
+      return NULL;
+    }
+  
   if (!bus_service_add_owner (service, owner_if_created,
                               transaction, error))
     {
index 5e9ece1..aba2989 100644 (file)
@@ -32,7 +32,7 @@
 typedef void (* BusServiceForeachFunction) (BusService       *service,
                                             void             *data);
 
-BusRegistry* bus_registry_new           (void);
+BusRegistry* bus_registry_new           (BusContext                  *context);
 void         bus_registry_ref           (BusRegistry                 *registry);
 void         bus_registry_unref         (BusRegistry                 *registry);
 BusService*  bus_registry_lookup        (BusRegistry                 *registry,
index 2b4a760..7f9423a 100644 (file)
@@ -1488,7 +1488,7 @@ dbus_connection_send_with_reply_and_block (DBusConnection     *connection,
       timeout_milliseconds = (end_tv_sec - tv_sec) * 1000 +
         (end_tv_usec - tv_usec) / 1000;
       _dbus_verbose ("%d milliseconds remain\n", timeout_milliseconds);
-      _dbus_assert (timeout_milliseconds > 0);
+      _dbus_assert (timeout_milliseconds >= 0);
       
       if (status == DBUS_DISPATCH_NEED_MEMORY)
         {
index 6bcc206..51a694a 100644 (file)
@@ -1167,7 +1167,7 @@ dbus_message_append_args_valist (DBusMessage *message,
        case DBUS_TYPE_STRING_ARRAY:
          {
            int len;
-           char **data;
+           const char **data;
            
            data = va_arg (var_args, const char **);
            len = va_arg (var_args, int);
index e0b0c98..c7eb737 100644 (file)
@@ -77,6 +77,10 @@ extern "C" {
 #define DBUS_SERVICE_REPLY_IN_QUEUE       0x2
 #define DBUS_SERVICE_REPLY_SERVICE_EXISTS 0x4
 #define DBUS_SERVICE_REPLY_ALREADY_OWNER  0x8
+
+/* Activation replies */
+#define DBUS_ACTIVATION_REPLY_ACTIVATED      0x0
+#define DBUS_ACTIVATION_REPLY_ALREADY_ACTIVE 0x1
   
 /* Messages */
 #define DBUS_MESSAGE_ACTIVATE_SERVICE      "org.freedesktop.DBus.ActivateService"  
@@ -88,7 +92,7 @@ extern "C" {
 #define DBUS_MESSAGE_SERVICE_CREATED       "org.freedesktop.DBus.ServiceCreated"
 #define DBUS_MESSAGE_SERVICE_DELETED       "org.freedesktop.DBus.ServiceDeleted"
 #define DBUS_MESSAGE_SERVICE_LOST          "org.freedesktop.DBus.ServiceLost"
-  
+
 #define DBUS_MESSAGE_LOCAL_DISCONNECT      "org.freedesktop.Local.Disconnect"
   
 #ifdef __cplusplus