summaryrefslogtreecommitdiffstats
path: root/hcid/dbus-service.c
diff options
context:
space:
mode:
authorJohan Hedberg <johan.hedberg@nokia.com>2007-01-19 19:20:34 +0000
committerJohan Hedberg <johan.hedberg@nokia.com>2007-01-19 19:20:34 +0000
commitf3d9f6a37d455da73950383a22d074684153dfbf (patch)
tree3accf3bf5c752af0dc42eb76eb090c57b9d7f8ae /hcid/dbus-service.c
parented95fffdbb414013f3dd29f8e400b0064f152793 (diff)
Never remove the child watch for services until the process has really died
Diffstat (limited to 'hcid/dbus-service.c')
-rw-r--r--hcid/dbus-service.c64
1 files changed, 37 insertions, 27 deletions
diff --git a/hcid/dbus-service.c b/hcid/dbus-service.c
index 2bfaa588..c390fc39 100644
--- a/hcid/dbus-service.c
+++ b/hcid/dbus-service.c
@@ -55,6 +55,7 @@
#define NAME_MATCH "interface=" DBUS_INTERFACE_DBUS ",member=NameOwnerChanged"
static GSList *services = NULL;
+static GSList *removed = NULL;
struct binary_record *binary_record_new()
{
@@ -438,6 +439,10 @@ static void service_died(GPid pid, gint status, gpointer data)
service->shutdown_timer = 0;
}
+ if (g_slist_find(removed, service)) {
+ removed = g_slist_remove(removed, service);
+ service_free(service);
+ }
}
@@ -457,14 +462,20 @@ static gboolean service_shutdown_timeout(gpointer data)
return FALSE;
}
-static void stop_service(struct service *service)
+static void stop_service(struct service *service, gboolean remove)
{
if (kill(service->pid, SIGTERM) < 0)
error("kill(%d, SIGTERM): %s (%d)", service->pid,
strerror(errno), errno);
+
service->shutdown_timer = g_timeout_add(SHUTDOWN_TIMEOUT,
service_shutdown_timeout,
service);
+
+ if (remove) {
+ services = g_slist_remove(services, service);
+ removed = g_slist_append(removed, service);
+ }
}
static gboolean service_startup_timeout(gpointer data)
@@ -521,8 +532,7 @@ static int start_service(struct service *service, DBusConnection *conn)
g_strfreev(argv);
- service->watch_id = g_child_watch_add(service->pid, service_died,
- service);
+ g_child_watch_add(service->pid, service_died, service);
debug("%s executed with PID %d", service->exec, service->pid);
@@ -557,7 +567,7 @@ static DBusHandlerResult stop(DBusConnection *conn,
if (!service->bus_name)
return error_failed(conn, msg, EPERM);
- stop_service(service);
+ stop_service(service, FALSE);
service->action = dbus_message_ref(msg);
@@ -801,15 +811,6 @@ static int unregister_service(struct service *service)
if (!dbus_connection_unregister_object_path(conn, service->object_path))
return -ENOMEM;
- signal = dbus_message_new_signal(BASE_PATH, MANAGER_INTERFACE,
- "ServiceRemoved");
- if (signal) {
- dbus_message_append_args(signal,
- DBUS_TYPE_STRING, &service->object_path,
- DBUS_TYPE_INVALID);
- send_message_and_unref(conn, signal);
- }
-
if (service->records)
unregister_service_records(service->records);
@@ -817,23 +818,32 @@ static int unregister_service(struct service *service)
name_listener_remove(get_dbus_connection(), service->bus_name,
(name_cb_t) service_exit, service);
- if (service->watch_id)
- g_source_remove(service->watch_id);
-
- if (service->pid && kill(service->pid, SIGKILL) < 0)
- error("kill(%d, SIGKILL): %s (%d)", service->pid,
- strerror(errno), errno);
-
- if (service->startup_timer)
- abort_startup(service, get_dbus_connection(), ECANCELED);
-
- if (service->shutdown_timer)
- g_timeout_remove(service->shutdown_timer);
+ signal = dbus_message_new_signal(service->object_path,
+ SERVICE_INTERFACE, "Stopped");
+ send_message_and_unref(conn, signal);
- services = g_slist_remove(services, service);
+ signal = dbus_message_new_signal(BASE_PATH, MANAGER_INTERFACE,
+ "ServiceRemoved");
+ if (signal) {
+ dbus_message_append_args(signal,
+ DBUS_TYPE_STRING, &service->object_path,
+ DBUS_TYPE_INVALID);
+ send_message_and_unref(conn, signal);
+ }
- service_free(service);
+ if (service->pid) {
+ if (service->startup_timer) {
+ abort_startup(service, get_dbus_connection(), ECANCELED);
+ services = g_slist_remove(services, service);
+ removed = g_slist_append(removed, service);
+ } else if (!service->shutdown_timer)
+ stop_service(service, TRUE);
+ } else {
+ services = g_slist_remove(services, service);
+ service_free(service);
+ }
+
return 0;
}