X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Ftask.c;h=97de7e351c9c1948321e451095395fa782eb45ef;hb=c189a9ab8a085447b775c7fbeb0a8050751b7f84;hp=d895a8628bbe6d2318c57bd0066974bb33f44bf2;hpb=d76088a3c6104f2569279086752a3f3cf1ea6adc;p=framework%2Fconnectivity%2Fconnman.git diff --git a/src/task.c b/src/task.c index d895a86..97de7e3 100644 --- a/src/task.c +++ b/src/task.c @@ -2,7 +2,7 @@ * * Connection Manager * - * Copyright (C) 2007-2010 Intel Corporation. All rights reserved. + * Copyright (C) 2007-2012 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -23,9 +23,11 @@ #include #endif +#include #include #include #include +#include #include @@ -39,6 +41,7 @@ struct notify_data { struct connman_task { char *path; pid_t pid; + guint child_watch; GPtrArray *argv; GPtrArray *envp; connman_task_exit_t exit_func; @@ -48,7 +51,7 @@ struct connman_task { static GHashTable *task_hash = NULL; -static volatile gint task_counter; +static volatile int task_counter; static DBusConnection *connection; @@ -69,6 +72,9 @@ static void free_task(gpointer data) if (task->pid > 0) kill(task->pid, SIGTERM); + if (task->child_watch > 0) + g_source_remove(task->child_watch); + g_ptr_array_foreach(task->envp, free_pointer, NULL); g_ptr_array_free(task->envp, TRUE); @@ -99,7 +105,7 @@ struct connman_task *connman_task_create(const char *program) if (task == NULL) return NULL; - counter = g_atomic_int_exchange_and_add(&task_counter, 1); + counter = __sync_fetch_and_add(&task_counter, 1); task->path = g_strdup_printf("/task/%d", counter); task->pid = -1; @@ -234,7 +240,7 @@ int connman_task_set_notify(struct connman_task *task, const char *member, notify->func = function; notify->data = user_data; - g_hash_table_insert(task->notify, g_strdup(member), notify); + g_hash_table_replace(task->notify, g_strdup(member), notify); return 0; } @@ -242,24 +248,35 @@ int connman_task_set_notify(struct connman_task *task, const char *member, static void task_died(GPid pid, gint status, gpointer user_data) { struct connman_task *task = user_data; + int exit_code; - if (WIFEXITED(status)) - DBG("task %p exit status %d", task, WEXITSTATUS(status)); - else + if (WIFEXITED(status)) { + exit_code = WEXITSTATUS(status); + DBG("task %p exit status %d", task, exit_code); + } else { + exit_code = 0; DBG("task %p signal %d", task, WTERMSIG(status)); + } g_spawn_close_pid(pid); task->pid = -1; + task->child_watch = 0; + if (task->exit_func) - task->exit_func(task, task->exit_data); + task->exit_func(task, exit_code, task->exit_data); } static void task_setup(gpointer user_data) { + sigset_t mask; struct connman_task *task = user_data; DBG("task %p", task); + + sigemptyset(&mask); + if (sigprocmask(SIG_SETMASK, &mask, NULL) < 0) + connman_error("Failed to clean signal mask"); } /** @@ -328,11 +345,49 @@ int connman_task_run(struct connman_task *task, return -EIO; } - g_child_watch_add(task->pid, task_died, task); + task->child_watch = g_child_watch_add(task->pid, task_died, task); return 0; } +static gboolean force_kill_timeout(gpointer user_data) +{ + pid_t pid = GPOINTER_TO_INT(user_data); + if (pid > 0) { + if (kill(pid, SIGKILL) == 0) + connman_warn("killing pid %d by force", pid); + } + + return FALSE; +} + +static gboolean kill_timeout(gpointer user_data) +{ + pid_t pid = GPOINTER_TO_INT(user_data); + if (pid > 0) { + if (kill(pid, SIGINT) == 0) + g_timeout_add_seconds(1, force_kill_timeout, + GINT_TO_POINTER(pid)); + } + + return FALSE; +} + +static gboolean check_kill(gpointer user_data) +{ + pid_t pid = GPOINTER_TO_INT(user_data); + if (pid > 0) { + if (kill(pid, 0) == 0) { + connman_info("pid %d was not killed, " + "retrying after 2 sec", pid); + g_timeout_add_seconds(2, kill_timeout, + GINT_TO_POINTER(pid)); + } + } + + return FALSE; +} + /** * connman_task_stop: * @task: task structure @@ -343,9 +398,13 @@ int connman_task_stop(struct connman_task *task) { DBG("task %p", task); - if (task->pid > 0) + if (task->pid > 0) { kill(task->pid, SIGTERM); + g_timeout_add_seconds(0, check_kill, + GINT_TO_POINTER(task->pid)); + } + return 0; } @@ -355,6 +414,7 @@ static DBusHandlerResult task_filter(DBusConnection *connection, struct connman_task *task; struct notify_data *notify; const char *path, *member; + DBusMessage *reply = NULL; if (dbus_message_get_type(message) != DBUS_MESSAGE_TYPE_METHOD_CALL) return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; @@ -371,30 +431,32 @@ static DBusHandlerResult task_filter(DBusConnection *connection, if (task == NULL) return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; - if (dbus_message_get_no_reply(message) == FALSE) { - DBusMessage *reply; - dbus_bool_t result; + member = dbus_message_get_member(message); + if (member == NULL) + goto send_reply; + + notify = g_hash_table_lookup(task->notify, member); + if (notify == NULL) + goto send_reply; + + if (notify->func) + reply = notify->func(task, message, notify->data); + +send_reply: + if (dbus_message_get_no_reply(message) == FALSE && + reply == NULL) { reply = dbus_message_new_method_return(message); if (reply == NULL) return DBUS_HANDLER_RESULT_NEED_MEMORY; + } - result = dbus_connection_send(connection, reply, NULL); + if (reply != NULL) { + dbus_connection_send(connection, reply, NULL); dbus_message_unref(reply); } - member = dbus_message_get_member(message); - if (member == NULL) - return DBUS_HANDLER_RESULT_HANDLED; - - notify = g_hash_table_lookup(task->notify, member); - if (notify == NULL) - return DBUS_HANDLER_RESULT_HANDLED; - - if (notify->func) - notify->func(task, message, notify->data); - return DBUS_HANDLER_RESULT_HANDLED; } @@ -409,7 +471,8 @@ int __connman_task_init(void) dbus_connection_add_filter(connection, task_filter, NULL, NULL); - g_atomic_int_set(&task_counter, 0); + task_counter = 0; + __sync_synchronize(); task_hash = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, free_task);