X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=bus%2Factivation.c;h=3682eecce7c2a7d5dd2d2b643cd1067e295b1457;hb=e8d396efef695b9868b0112c4a6266c97678fa8a;hp=54ddd948b669b0fc3a16d797973ddeb8bf461b78;hpb=2250539aeee0569f8861841d1f5ff16f1539715e;p=platform%2Fupstream%2Fdbus.git diff --git a/bus/activation.c b/bus/activation.c index 54ddd94..3682eec 100644 --- a/bus/activation.c +++ b/bus/activation.c @@ -45,6 +45,10 @@ struct BusActivation DBusHashTable *pending_activations; char *server_address; BusContext *context; + int n_pending_activations; /**< This is in fact the number of BusPendingActivationEntry, + * i.e. number of pending activation requests, not pending + * activations per se + */ }; typedef struct @@ -63,9 +67,11 @@ struct BusPendingActivationEntry typedef struct { + int refcount; BusActivation *activation; char *service_name; DBusList *entries; + int n_entries; DBusBabysitter *babysitter; DBusTimeout *timeout; unsigned int timeout_added : 1; @@ -90,22 +96,35 @@ handle_timeout_callback (DBusTimeout *timeout, BusPendingActivation *pending_activation = data; while (!dbus_timeout_handle (pending_activation->timeout)) - bus_wait_for_memory (); + _dbus_wait_for_memory (); +} + +static void +bus_pending_activation_ref (BusPendingActivation *pending_activation) +{ + _dbus_assert (pending_activation->refcount > 0); + pending_activation->refcount += 1; } static void -bus_pending_activation_free (BusPendingActivation *pending_activation) +bus_pending_activation_unref (BusPendingActivation *pending_activation) { DBusList *link; if (pending_activation == NULL) /* hash table requires this */ return; + _dbus_assert (pending_activation->refcount > 0); + pending_activation->refcount -= 1; + + if (pending_activation->refcount > 0) + return; + if (pending_activation->timeout_added) { - bus_loop_remove_timeout (bus_context_get_loop (pending_activation->activation->context), - pending_activation->timeout, - handle_timeout_callback, pending_activation); + _dbus_loop_remove_timeout (bus_context_get_loop (pending_activation->activation->context), + pending_activation->timeout, + handle_timeout_callback, pending_activation); pending_activation->timeout_added = FALSE; } @@ -136,6 +155,11 @@ bus_pending_activation_free (BusPendingActivation *pending_activation) link = _dbus_list_get_next_link (&pending_activation->entries, link); } _dbus_list_clear (&pending_activation->entries); + + pending_activation->activation->n_pending_activations -= + pending_activation->n_entries; + + _dbus_assert (pending_activation->activation->n_pending_activations >= 0); dbus_free (pending_activation); } @@ -380,6 +404,7 @@ bus_activation_new (BusContext *context, activation->refcount = 1; activation->context = context; + activation->n_pending_activations = 0; if (!_dbus_string_copy_data (address, &activation->server_address)) { @@ -396,7 +421,7 @@ bus_activation_new (BusContext *context, } activation->pending_activations = _dbus_hash_table_new (DBUS_HASH_STRING, NULL, - (DBusFreeFunction)bus_pending_activation_free); + (DBusFreeFunction)bus_pending_activation_unref); if (activation->pending_activations == NULL) { @@ -466,6 +491,75 @@ child_setup (void *data) } } +typedef struct +{ + BusPendingActivation *pending_activation; + DBusPreallocatedHash *hash_entry; +} RestorePendingData; + +static void +restore_pending (void *data) +{ + RestorePendingData *d = data; + + _dbus_assert (d->pending_activation != NULL); + _dbus_assert (d->hash_entry != NULL); + + _dbus_verbose ("Restoring pending activation for service %s, has timeout = %d\n", + d->pending_activation->service_name, + d->pending_activation->timeout_added); + + _dbus_hash_table_insert_string_preallocated (d->pending_activation->activation->pending_activations, + d->hash_entry, + d->pending_activation->service_name, d->pending_activation); + + bus_pending_activation_ref (d->pending_activation); + + d->hash_entry = NULL; +} + +static void +free_pending_restore_data (void *data) +{ + RestorePendingData *d = data; + + if (d->hash_entry) + _dbus_hash_table_free_preallocated_entry (d->pending_activation->activation->pending_activations, + d->hash_entry); + + bus_pending_activation_unref (d->pending_activation); + + dbus_free (d); +} + +static dbus_bool_t +add_restore_pending_to_transaction (BusTransaction *transaction, + BusPendingActivation *pending_activation) +{ + RestorePendingData *d; + + d = dbus_new (RestorePendingData, 1); + if (d == NULL) + return FALSE; + + d->pending_activation = pending_activation; + d->hash_entry = _dbus_hash_table_preallocate_entry (d->pending_activation->activation->pending_activations); + + bus_pending_activation_ref (d->pending_activation); + + if (d->hash_entry == NULL || + !bus_transaction_add_cancel_hook (transaction, restore_pending, d, + free_pending_restore_data)) + { + free_pending_restore_data (d); + return FALSE; + } + + _dbus_verbose ("Saved pending activation to be restored if the transaction fails\n"); + + return TRUE; +} + dbus_bool_t bus_activation_service_created (BusActivation *activation, const char *service_name, @@ -499,8 +593,7 @@ bus_activation_service_created (BusActivation *activation, goto error; } - if (!dbus_message_set_sender (message, DBUS_SERVICE_DBUS) || - !dbus_message_append_args (message, + if (!dbus_message_append_args (message, DBUS_TYPE_UINT32, DBUS_ACTIVATION_REPLY_ACTIVATED, 0)) { @@ -509,25 +602,31 @@ bus_activation_service_created (BusActivation *activation, goto error; } - if (!bus_transaction_send_message (transaction, entry->connection, message)) + if (!bus_transaction_send_from_driver (transaction, entry->connection, message)) { dbus_message_unref (message); BUS_SET_OOM (error); goto error; } - + dbus_message_unref (message); } link = next; } + + if (!add_restore_pending_to_transaction (transaction, pending_activation)) + { + _dbus_verbose ("Could not add cancel hook to transaction to revert removing pending activation\n"); + BUS_SET_OOM (error); + goto error; + } _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; } @@ -542,7 +641,6 @@ try_send_activation_failure (BusPendingActivation *pending_activation, const DBusError *how) { BusActivation *activation; - DBusMessage *message; DBusList *link; BusTransaction *transaction; @@ -560,27 +658,13 @@ try_send_activation_failure (BusPendingActivation *pending_activation, if (dbus_connection_get_is_connected (entry->connection)) { - message = dbus_message_new_error_reply (entry->activation_message, - how->name, - how->message); - if (!message) + if (!bus_transaction_send_error_reply (transaction, + entry->connection, + how, + entry->activation_message)) goto error; - - if (!dbus_message_set_sender (message, DBUS_SERVICE_DBUS)) - { - dbus_message_unref (message); - goto error; - } - - if (!bus_transaction_send_message (transaction, entry->connection, message)) - { - dbus_message_unref (message); - goto error; - } - - dbus_message_unref (message); } - + link = next; } @@ -604,7 +688,7 @@ pending_activation_failed (BusPendingActivation *pending_activation, { /* FIXME use preallocated OOM messages instead of bus_wait_for_memory() */ while (!try_send_activation_failure (pending_activation, how)) - bus_wait_for_memory (); + _dbus_wait_for_memory (); /* Destroy this pending activation */ _dbus_hash_table_remove_string (pending_activation->activation->pending_activations, @@ -624,8 +708,18 @@ babysitter_watch_callback (DBusWatch *watch, _dbus_babysitter_ref (babysitter); - retval = _dbus_babysitter_handle_watch (babysitter, watch, condition); - + retval = dbus_watch_handle (watch, condition); + + /* FIXME this is broken in the same way that + * connection watches used to be; there should be + * a separate callback for status change, instead + * of doing "if we handled a watch status might + * have changed" + * + * Fixing this lets us move dbus_watch_handle + * calls into dbus-mainloop.c + */ + if (_dbus_babysitter_get_child_exited (babysitter)) { DBusError error; @@ -650,9 +744,9 @@ add_babysitter_watch (DBusWatch *watch, { BusPendingActivation *pending_activation = data; - return bus_loop_add_watch (bus_context_get_loop (pending_activation->activation->context), - watch, babysitter_watch_callback, pending_activation, - NULL); + return _dbus_loop_add_watch (bus_context_get_loop (pending_activation->activation->context), + watch, babysitter_watch_callback, pending_activation, + NULL); } static void @@ -661,8 +755,8 @@ remove_babysitter_watch (DBusWatch *watch, { BusPendingActivation *pending_activation = data; - bus_loop_remove_watch (bus_context_get_loop (pending_activation->activation->context), - watch, babysitter_watch_callback, pending_activation); + _dbus_loop_remove_watch (bus_context_get_loop (pending_activation->activation->context), + watch, babysitter_watch_callback, pending_activation); } static dbus_bool_t @@ -690,6 +784,45 @@ pending_activation_timed_out (void *data) return TRUE; } +static void +cancel_pending (void *data) +{ + BusPendingActivation *pending_activation = data; + + _dbus_verbose ("Canceling pending activation of %s\n", + pending_activation->service_name); + + if (pending_activation->babysitter) + _dbus_babysitter_kill_child (pending_activation->babysitter); + + _dbus_hash_table_remove_string (pending_activation->activation->pending_activations, + pending_activation->service_name); +} + +static void +free_pending_cancel_data (void *data) +{ + BusPendingActivation *pending_activation = data; + + bus_pending_activation_unref (pending_activation); +} + +static dbus_bool_t +add_cancel_pending_to_transaction (BusTransaction *transaction, + BusPendingActivation *pending_activation) +{ + if (!bus_transaction_add_cancel_hook (transaction, cancel_pending, + pending_activation, + free_pending_cancel_data)) + return FALSE; + + bus_pending_activation_ref (pending_activation); + + _dbus_verbose ("Saved pending activation to be canceled if the transaction fails\n"); + + return TRUE; +} + dbus_bool_t bus_activation_activate_service (BusActivation *activation, DBusConnection *connection, @@ -707,6 +840,15 @@ bus_activation_activate_service (BusActivation *activation, dbus_bool_t retval; _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + if (activation->n_pending_activations >= + bus_context_get_max_pending_activations (activation->context)) + { + dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED, + "The maximum number of pending activations has been reached, activation of %s failed", + service_name); + return FALSE; + } entry = _dbus_hash_table_lookup_string (activation->entries, service_name); @@ -722,28 +864,34 @@ bus_activation_activate_service (BusActivation *activation, _dbus_string_init_const (&service_str, service_name); if (bus_registry_lookup (bus_context_get_registry (activation->context), &service_str) != NULL) { + _dbus_verbose ("Service \"%s\" is already active\n", service_name); + message = dbus_message_new_reply (activation_message); if (!message) { + _dbus_verbose ("No memory to create reply to activate message\n"); BUS_SET_OOM (error); return FALSE; } - if (!dbus_message_set_sender (message, DBUS_SERVICE_DBUS) || - !dbus_message_append_args (message, + if (!dbus_message_append_args (message, DBUS_TYPE_UINT32, DBUS_ACTIVATION_REPLY_ALREADY_ACTIVE, 0)) { + _dbus_verbose ("No memory to set args of reply to activate message\n"); BUS_SET_OOM (error); dbus_message_unref (message); return FALSE; } - retval = bus_transaction_send_message (transaction, connection, message); + retval = bus_transaction_send_from_driver (transaction, connection, message); dbus_message_unref (message); if (!retval) - BUS_SET_OOM (error); + { + _dbus_verbose ("Failed to send reply\n"); + BUS_SET_OOM (error); + } return retval; } @@ -751,6 +899,7 @@ bus_activation_activate_service (BusActivation *activation, pending_activation_entry = dbus_new0 (BusPendingActivationEntry, 1); if (!pending_activation_entry) { + _dbus_verbose ("Failed to create pending activation entry\n"); BUS_SET_OOM (error); return FALSE; } @@ -766,29 +915,38 @@ bus_activation_activate_service (BusActivation *activation, { if (!_dbus_list_append (&pending_activation->entries, pending_activation_entry)) { + _dbus_verbose ("Failed to append a new entry to pending activation\n"); + BUS_SET_OOM (error); bus_pending_activation_entry_free (pending_activation_entry); - return FALSE; } + + pending_activation->n_entries += 1; + pending_activation->activation->n_pending_activations += 1; } else { pending_activation = dbus_new0 (BusPendingActivation, 1); if (!pending_activation) { + _dbus_verbose ("Failed to create pending activation\n"); + BUS_SET_OOM (error); bus_pending_activation_entry_free (pending_activation_entry); return FALSE; } pending_activation->activation = activation; + pending_activation->refcount = 1; pending_activation->service_name = _dbus_strdup (service_name); if (!pending_activation->service_name) { + _dbus_verbose ("Failed to copy service name for pending activation\n"); + BUS_SET_OOM (error); - bus_pending_activation_free (pending_activation); + bus_pending_activation_unref (pending_activation); bus_pending_activation_entry_free (pending_activation_entry); return FALSE; } @@ -800,20 +958,24 @@ bus_activation_activate_service (BusActivation *activation, NULL); if (!pending_activation->timeout) { + _dbus_verbose ("Failed to create timeout for pending activation\n"); + BUS_SET_OOM (error); - bus_pending_activation_free (pending_activation); + bus_pending_activation_unref (pending_activation); bus_pending_activation_entry_free (pending_activation_entry); return FALSE; } - if (!bus_loop_add_timeout (bus_context_get_loop (activation->context), - pending_activation->timeout, - handle_timeout_callback, - pending_activation, - NULL)) + if (!_dbus_loop_add_timeout (bus_context_get_loop (activation->context), + pending_activation->timeout, + handle_timeout_callback, + pending_activation, + NULL)) { + _dbus_verbose ("Failed to add timeout for pending activation\n"); + BUS_SET_OOM (error); - bus_pending_activation_free (pending_activation); + bus_pending_activation_unref (pending_activation); bus_pending_activation_entry_free (pending_activation_entry); return FALSE; } @@ -822,20 +984,37 @@ bus_activation_activate_service (BusActivation *activation, if (!_dbus_list_append (&pending_activation->entries, pending_activation_entry)) { + _dbus_verbose ("Failed to add entry to just-created pending activation\n"); + BUS_SET_OOM (error); - bus_pending_activation_free (pending_activation); + bus_pending_activation_unref (pending_activation); bus_pending_activation_entry_free (pending_activation_entry); return FALSE; } + + pending_activation->n_entries += 1; + pending_activation->activation->n_pending_activations += 1; if (!_dbus_hash_table_insert_string (activation->pending_activations, - pending_activation->service_name, pending_activation)) + pending_activation->service_name, + pending_activation)) { + _dbus_verbose ("Failed to put pending activation in hash table\n"); + BUS_SET_OOM (error); - bus_pending_activation_free (pending_activation); + bus_pending_activation_unref (pending_activation); return FALSE; } } + + if (!add_cancel_pending_to_transaction (transaction, pending_activation)) + { + _dbus_verbose ("Failed to add pending activation cancel hook to transaction\n"); + BUS_SET_OOM (error); + _dbus_hash_table_remove_string (activation->pending_activations, + pending_activation->service_name); + return FALSE; + } /* FIXME we need to support a full command line, not just a single * argv[0] @@ -849,8 +1028,8 @@ bus_activation_activate_service (BusActivation *activation, child_setup, activation, error)) { - _dbus_hash_table_remove_string (activation->pending_activations, - pending_activation->service_name); + _dbus_verbose ("Failed to spawn child\n"); + _DBUS_ASSERT_ERROR_IS_SET (error); return FALSE; } @@ -864,9 +1043,7 @@ bus_activation_activate_service (BusActivation *activation, NULL)) { BUS_SET_OOM (error); - - _dbus_hash_table_remove_string (activation->pending_activations, - pending_activation->service_name); + _dbus_verbose ("Failed to set babysitter watch functions\n"); return FALSE; }