a6362e4c830820a80f2d5ba9e46589638c7bad2e
[framework/connectivity/connman.git] / plugins / task.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2010  Intel Corporation. All rights reserved.
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License version 2 as
9  *  published by the Free Software Foundation.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <unistd.h>
27 #include <sys/wait.h>
28
29 #include <glib.h>
30
31 #include <connman/log.h>
32
33 #include "task.h"
34
35 struct task_data {
36         pid_t pid;
37         int index;
38         task_cb_t callback;
39         void *user_data;
40 };
41
42 static GSList *task_list = NULL;
43
44 struct task_data *task_find_by_pid(pid_t pid)
45 {
46         GSList *list;
47
48         for (list = task_list; list; list = list->next) {
49                 struct task_data *task = list->data;
50
51                 if (task->pid == pid)
52                         return task;
53         }
54
55         return NULL;
56 }
57
58 struct task_data *task_find_by_index(int index)
59 {
60         GSList *list;
61
62         for (list = task_list; list; list = list->next) {
63                 struct task_data *task = list->data;
64
65                 if (task->index == index)
66                         return task;
67         }
68
69         return NULL;
70 }
71
72 static void task_died(GPid pid, gint status, gpointer user_data)
73 {
74         struct task_data *task = user_data;
75
76         if (WIFEXITED(status))
77                 DBG("task %p exit status %d", task, WEXITSTATUS(status));
78         else
79                 DBG("task %p signal %d", task, WTERMSIG(status));
80
81         g_spawn_close_pid(pid);
82         task->pid = 0;
83
84         task_list = g_slist_remove(task_list, task);
85
86         if (task->callback)
87                 task->callback(task->index, task->user_data);
88
89         g_free(task);
90 }
91
92 static void task_setup(gpointer user_data)
93 {
94         struct task_data *task = user_data;
95
96         DBG("task %p", task);
97 }
98
99 struct task_data *task_spawn(int index, char **argv, char **envp,
100                                         task_cb_t callback, void *user_data)
101 {
102         GSpawnFlags flags = G_SPAWN_DO_NOT_REAP_CHILD |
103                                                 G_SPAWN_STDOUT_TO_DEV_NULL;
104         struct task_data *task;
105
106         DBG("index %d", index);
107
108         task = g_try_new0(struct task_data, 1);
109         if (task == NULL)
110                 return NULL;
111
112         task->index = index;
113
114         task->callback  = callback;
115         task->user_data = user_data;
116
117         if (g_spawn_async(NULL, argv, envp, flags,
118                                 task_setup, task, &task->pid, NULL) == FALSE) {
119                 connman_error("Failed to spawn task");
120                 return NULL;
121         }
122
123         task_list = g_slist_append(task_list, task);
124
125         g_child_watch_add(task->pid, task_died, task);
126
127         DBG("task %p pid %d", task, task->pid);
128
129         return task;
130 }
131
132 int task_kill(struct task_data *task)
133 {
134         DBG("task %p", task);
135
136         if (task->pid > 0)
137                 kill(task->pid, SIGTERM);
138
139         return 0;
140 }
141
142 void *task_get_data(struct task_data *task)
143 {
144         return task->user_data;
145 }