87b02b0c14e9d34128271e6bbfb4990197fab9be
[src/app-framework-main.git] / src / appfwk-run.c
1 /*
2  Copyright 2015 IoT.bzh
3
4  Licensed under the Apache License, Version 2.0 (the "License");
5  you may not use this file except in compliance with the License.
6  You may obtain a copy of the License at
7
8      http://www.apache.org/licenses/LICENSE-2.0
9
10  Unless required by applicable law or agreed to in writing, software
11  distributed under the License is distributed on an "AS IS" BASIS,
12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  See the License for the specific language governing permissions and
14  limitations under the License.
15 */
16
17 #include <unistd.h>
18 #include <signal.h>
19
20
21
22 #include <stdlib.h>
23 #include <assert.h>
24 #include <string.h>
25 #include <errno.h>
26 #include <dirent.h>
27 #include <fcntl.h>
28 #include <sys/types.h>
29
30 #include <json.h>
31
32 #include <wgt-info.h>
33
34
35 enum appstate {
36         as_starting,
37         as_running,
38         as_stopped,
39         as_terminating,
40         as_terminated
41 };
42
43 struct apprun {
44         struct apprun *next_by_runid;
45         struct apprun *next_by_pgid;
46         int runid;
47         pid_t backend;
48         pid_t frontend;
49         enum appstate state;
50         json_object *appli;
51 };
52
53 #define ROOT_RUNNERS_COUNT  32
54 #define MAX_RUNNER_COUNT    32767
55
56 static struct apprun *runners_by_runid[ROOT_RUNNERS_COUNT];
57 static struct apprun *runners_by_pgid[ROOT_RUNNERS_COUNT];
58 static int runnercount = 0;
59 static int runnerid = 0;
60
61 /****************** manages pgids **********************/
62
63 /* get a runner by its pgid */
64 static struct apprun *runner_of_pgid(pid_t pgid)
65 {
66         struct apprun *result = runners_by_pgid[(int)(pgid & (ROOT_RUNNERS_COUNT - 1))];
67         while (result && result->backend != pgid)
68                 result = result->next_by_pgid;
69         return result;
70 }
71
72 /* insert a runner for its pgid */
73 static void pgid_insert(struct apprun *runner)
74 {
75         struct apprun **prev = &runners_by_runid[(int)(runner->backend & (ROOT_RUNNERS_COUNT - 1))];
76         runner->next_by_pgid = *prev;
77         *prev = runner;
78 }
79
80 /* remove a runner for its pgid */
81 static void pgid_remove(struct apprun *runner)
82 {
83         struct apprun **prev = &runners_by_runid[(int)(runner->backend & (ROOT_RUNNERS_COUNT - 1))];
84         runner->next_by_pgid = *prev;
85         *prev = runner;
86 }
87
88 /****************** manages pids **********************/
89
90 /* get a runner by its pid */
91 static struct apprun *runner_of_pid(pid_t pid)
92 {
93         /* try avoiding system call */
94         struct apprun *result = runner_of_pgid(pid);
95         if (result == NULL)
96                 result = runner_of_pgid(getpgid(pid));
97         return result;
98 }
99
100 /****************** manages runners (by runid) **********************/
101
102 /* get a runner by its runid */
103 static struct apprun *getrunner(int runid)
104 {
105         struct apprun *result = runners_by_runid[runid & (ROOT_RUNNERS_COUNT - 1)];
106         while (result && result->runid != runid)
107                 result = result->next_by_runid;
108         return result;
109 }
110
111 /* free an existing runner */
112 static void freerunner(struct apprun *runner)
113 {
114         struct apprun **prev = &runners_by_runid[runner->runid & (ROOT_RUNNERS_COUNT - 1)];
115         assert(*prev);
116         while(*prev != runner) {
117                 prev = &(*prev)->next_by_runid;
118                 assert(*prev);
119         }
120         *prev = runner->next_by_runid;
121         json_object_put(runner->appli);
122         free(runner);
123         runnercount--;
124 }
125
126 /* create a new runner */
127 static struct apprun *createrunner(json_object *appli)
128 {
129         struct apprun *result;
130         struct apprun **prev;
131
132         if (runnercount >= MAX_RUNNER_COUNT)
133                 return NULL;
134         do {
135                 runnerid++;
136                 if (runnerid > MAX_RUNNER_COUNT)
137                         runnerid = 1;
138         } while(getrunner(runnerid));
139         result = calloc(1, sizeof * result);
140         if (result) {
141                 prev = &runners_by_runid[runnerid & (ROOT_RUNNERS_COUNT - 1)];
142                 result->next_by_runid = *prev;
143                 result->next_by_pgid = NULL;
144                 result->runid = runnerid;
145                 result->backend = 0;
146                 result->frontend = 0;
147                 result->state = as_starting;
148                 result->appli = json_object_get(appli);
149                 *prev = result;
150                 runnercount++;
151         }
152         return result;
153 }
154
155 /**************** signaling ************************/
156
157 static void started(int runid)
158 {
159 }
160
161 static void stopped(int runid)
162 {
163 }
164
165 static void continued(int runid)
166 {
167 }
168
169 static void terminated(int runid)
170 {
171 }
172
173 static void removed(int runid)
174 {
175 }
176
177 /**************** running ************************/
178
179 static int killrunner(int runid, int sig, enum appstate tostate)
180 {
181         int rc;
182         struct apprun *runner = getrunner(runid);
183         if (runner == NULL) {
184                 errno = ENOENT;
185                 rc = -1;
186         }
187         else if (runner->state != as_running && runner->state != as_stopped) {
188                 errno = EPERM;
189                 rc = -1;
190         }
191         else if (runner->state == tostate) {
192                 rc = 0;
193         }
194         else {
195                 rc = killpg(runner->backend, sig);
196                 if (!rc)
197                         runner->state = tostate;
198         }
199         return rc;
200 }
201
202 /**************** API handling ************************/
203
204 int appfwk_run_start(struct json_object *appli)
205 {
206         return -1;
207 }
208
209 int appfwk_run_terminate(int runid)
210 {
211         return killrunner(runid, SIGTERM, as_terminating);
212 }
213
214 int appfwk_run_stop(int runid)
215 {
216         return killrunner(runid, SIGSTOP, as_stopped);
217 }
218
219 int appfwk_run_continue(int runid)
220 {
221         return killrunner(runid, SIGCONT, as_running);
222 }
223
224 static json_object *mkstate(struct apprun *runner, const char **runidstr)
225 {
226         const char *state;
227         struct json_object *result, *obj, *runid;
228         int rc;
229
230         /* the structure */
231         result = json_object_new_object();
232         if (result == NULL)
233                 goto error;
234
235         /* the runid */
236         runid = json_object_new_int(runner->runid);
237         if (runid == NULL)
238                 goto error2;
239         json_object_object_add(result, "runid", obj); /* TODO TEST STATUS */
240
241         /* the state */
242         switch(runner->state) {
243         case as_starting:
244         case as_running:
245                 state = "running";
246                 break;
247         case as_stopped:
248                 state = "stopped";
249                 break;
250         default:
251                 state = "terminated";
252                 break;
253         }
254         obj = json_object_new_string(state);
255         if (obj == NULL)
256                 goto error2;
257         json_object_object_add(result, "state", obj); /* TODO TEST STATUS */
258
259         /* the application id */
260         rc = json_object_object_get_ex(runner->appli, "public", &obj);
261         assert(rc);
262         rc = json_object_object_get_ex(obj, "id", &obj);
263         assert(rc);
264         json_object_object_add(result, "id", obj); /* TODO TEST STATUS */
265         json_object_get(obj);
266
267         /* done */
268         if (runidstr)
269                 *runidstr = json_object_get_string(runid);
270         return result;
271
272 error2:
273         json_object_put(result);
274 error:
275         errno = ENOMEM;
276         return NULL;
277 }
278
279 struct json_object *appfwk_run_list()
280 {
281         struct json_object *result, *obj;
282         struct apprun *runner;
283         const char *runidstr;
284         int i;
285
286         /* creates the object */
287         result = json_object_new_object();
288         if (result == NULL) {
289                 errno = ENOMEM;
290                 return NULL;            
291         }
292
293         for (i = 0 ; i < ROOT_RUNNERS_COUNT ; i++) {
294                 for (runner = runners_by_runid[i] ; runner ; runner = runner->next_by_runid) {
295                         if (runner->state != as_terminating && runner->state != as_terminated) {
296                                 obj = mkstate(runner, &runidstr);
297                                 if (obj == NULL) {
298                                         json_object_put(result);
299                                         return NULL;
300                                 }
301                                 /* TODO status ? */
302                                 json_object_object_add(result, runidstr, obj);
303                         }
304                 }
305         }
306         return result;
307 }
308
309 struct json_object *appfwk_run_state(int runid)
310 {
311         struct apprun *runner = getrunner(runid);
312         if (runner == NULL || runner->state == as_terminating || runner->state == as_terminated) {
313                 errno = ENOENT;
314                 return NULL;
315         }
316         return mkstate(runner, NULL);
317 }
318