blob: 27479e49850a20d946f8189da0d3efc4e37d8310 [file] [log] [blame]
/*
*
* Connection Manager
*
* Copyright (C) 2007-2009 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
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <unistd.h>
#include <sys/wait.h>
#include <glib.h>
#include <connman/log.h>
#include "task.h"
#define _DBG_TASK(fmt, arg...) DBG(DBG_TASK, fmt, ## arg)
struct task_data {
pid_t pid;
int index;
task_cb_t callback;
void *user_data;
};
static GSList *task_list = NULL;
struct task_data *task_find_by_pid(pid_t pid)
{
GSList *list;
for (list = task_list; list; list = list->next) {
struct task_data *task = list->data;
if (task->pid == pid)
return task;
}
return NULL;
}
struct task_data *task_find_by_index(int index)
{
GSList *list;
for (list = task_list; list; list = list->next) {
struct task_data *task = list->data;
if (task->index == index)
return task;
}
return NULL;
}
static void task_died(GPid pid, gint status, gpointer user_data)
{
struct task_data *task = user_data;
if (WIFEXITED(status))
_DBG_TASK("task %p exit status %d", task, WEXITSTATUS(status));
else
_DBG_TASK("task %p signal %d", task, WTERMSIG(status));
g_spawn_close_pid(pid);
task->pid = 0;
task_list = g_slist_remove(task_list, task);
if (task->callback)
task->callback(task->index, task->user_data);
g_free(task);
}
static void task_setup(gpointer user_data)
{
struct task_data *task = user_data;
_DBG_TASK("task %p", task);
}
struct task_data *task_spawn(int index, char **argv, char **envp,
task_cb_t callback, void *user_data)
{
GSpawnFlags flags = G_SPAWN_DO_NOT_REAP_CHILD |
G_SPAWN_STDOUT_TO_DEV_NULL;
struct task_data *task;
_DBG_TASK("index %d", index);
task = g_try_new0(struct task_data, 1);
if (task == NULL)
return NULL;
task->index = index;
task->callback = callback;
task->user_data = user_data;
if (g_spawn_async(NULL, argv, envp, flags,
task_setup, task, &task->pid, NULL) == FALSE) {
connman_error("Failed to spawn task");
return NULL;
}
task_list = g_slist_append(task_list, task);
g_child_watch_add(task->pid, task_died, task);
_DBG_TASK("task %p pid %d", task, task->pid);
return task;
}
int task_kill(struct task_data *task)
{
_DBG_TASK("task %p", task);
if (task->pid > 0)
kill(task->pid, SIGTERM);
return 0;
}
void *task_get_data(struct task_data *task)
{
return task->user_data;
}