From 3f4086f0fdd1cc7fc03585ec9f750897fb3c1d55 Mon Sep 17 00:00:00 2001 From: Anders Carlsson Date: Sun, 16 Mar 2003 22:25:18 +0000 Subject: 2003-03-16 Anders Carlsson * 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. --- bus/activation.c | 241 +++++++++++++++++++++++++++++++++++++++++++++++++++-- bus/activation.h | 18 ++-- bus/bus.c | 4 +- bus/desktop-file.c | 6 +- bus/driver.c | 4 +- bus/services.c | 16 +++- bus/services.h | 2 +- 7 files changed, 268 insertions(+), 23 deletions(-) (limited to 'bus') diff --git a/bus/activation.c b/bus/activation.c index ba130edd..c7d08baa 100644 --- a/bus/activation.c +++ b/bus/activation.c @@ -22,9 +22,11 @@ */ #include "activation.h" #include "desktop-file.h" +#include "services.h" #include "utils.h" #include #include +#include #include #include #include @@ -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; } diff --git a/bus/activation.h b/bus/activation.h index 4e363c92..1fd416ea 100644 --- a/bus/activation.h +++ b/bus/activation.h @@ -27,15 +27,19 @@ #include #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 */ diff --git a/bus/bus.c b/bus/bus.c index 4319e5fe..589dda1b 100644 --- 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); diff --git a/bus/desktop-file.c b/bus/desktop-file.c index 65a0d76f..f45a997e 100644 --- a/bus/desktop-file.c +++ b/bus/desktop-file.c @@ -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]; } diff --git a/bus/driver.c b/bus/driver.c index 09ec18af..98085fc7 100644 --- a/bus/driver.c +++ b/bus/driver.c @@ -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; diff --git a/bus/services.c b/bus/services.c index 92f6cdf4..821cb4af 100644 --- a/bus/services.c +++ b/bus/services.c @@ -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)) { diff --git a/bus/services.h b/bus/services.h index 5e9ece18..aba2989a 100644 --- a/bus/services.h +++ b/bus/services.h @@ -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, -- cgit