4 author: José Bollo <jose.bollo@iot.bzh>
6 Licensed under the Apache License, Version 2.0 (the "License");
7 you may not use this file except in compliance with the License.
8 You may obtain a copy of the License at
10 http://www.apache.org/licenses/LICENSE-2.0
12 Unless required by applicable law or agreed to in writing, software
13 distributed under the License is distributed on an "AS IS" BASIS,
14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 See the License for the specific language governing permissions and
16 limitations under the License.
23 #include <sys/types.h>
33 #include "utils-dir.h"
34 #include "af-launch.h"
45 struct apprun *next_by_runid;
46 struct apprun *next_by_pgid;
48 pid_t pids[2]; /* 0: group leader, 1: slave (appli) */
53 #define ROOT_RUNNERS_COUNT 32
54 #define MAX_RUNNER_COUNT 32767
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;
61 static const char fwk_user_app_dir[] = FWK_USER_APP_DIR;
62 static char *homeappdir;
64 /****************** manages pgids **********************/
66 /* get a runner by its pgid */
67 static struct apprun *runner_of_pgid(pid_t pgid)
69 struct apprun *result = runners_by_pgid[(int)(pgid & (ROOT_RUNNERS_COUNT - 1))];
70 while (result && result->pids[0] != pgid)
71 result = result->next_by_pgid;
75 /* insert a runner for its pgid */
76 static void pgid_insert(struct apprun *runner)
78 struct apprun **prev = &runners_by_runid[(int)(runner->pids[0] & (ROOT_RUNNERS_COUNT - 1))];
79 runner->next_by_pgid = *prev;
83 /* remove a runner for its pgid */
84 static void pgid_remove(struct apprun *runner)
86 struct apprun **prev = &runners_by_runid[(int)(runner->pids[0] & (ROOT_RUNNERS_COUNT - 1))];
87 runner->next_by_pgid = *prev;
91 /****************** manages pids **********************/
93 /* get a runner by its pid */
94 static struct apprun *runner_of_pid(pid_t pid)
96 /* try avoiding system call */
97 struct apprun *result = runner_of_pgid(pid);
99 result = runner_of_pgid(getpgid(pid));
100 if (result && result->pids[1] != pid)
106 /****************** manages runners (by runid) **********************/
108 /* get a runner by its runid */
109 static struct apprun *getrunner(int runid)
111 struct apprun *result = runners_by_runid[runid & (ROOT_RUNNERS_COUNT - 1)];
112 while (result && result->runid != runid)
113 result = result->next_by_runid;
117 /* free an existing runner */
118 static void freerunner(struct apprun *runner)
120 struct apprun **prev = &runners_by_runid[runner->runid & (ROOT_RUNNERS_COUNT - 1)];
122 while(*prev != runner) {
123 prev = &(*prev)->next_by_runid;
126 *prev = runner->next_by_runid;
127 json_object_put(runner->appli);
132 /* create a new runner */
133 static struct apprun *createrunner(json_object *appli)
135 struct apprun *result;
136 struct apprun **prev;
138 if (runnercount >= MAX_RUNNER_COUNT) {
144 if (runnerid > MAX_RUNNER_COUNT)
146 } while(getrunner(runnerid));
147 result = calloc(1, sizeof * result);
151 prev = &runners_by_runid[runnerid & (ROOT_RUNNERS_COUNT - 1)];
152 result->next_by_runid = *prev;
153 result->next_by_pgid = NULL;
154 result->runid = runnerid;
155 result->pids[0] = result->pids[1] = 0;
156 result->state = as_starting;
157 result->appli = json_object_get(appli);
164 /**************** signaling ************************/
166 static void started(int runid)
170 static void stopped(int runid)
174 static void continued(int runid)
178 static void terminated(int runid)
182 static void removed(int runid)
186 /**************** running ************************/
188 static int killrunner(int runid, int sig, enum appstate tostate)
191 struct apprun *runner = getrunner(runid);
192 if (runner == NULL) {
196 else if (runner->state != as_running && runner->state != as_stopped) {
200 else if (runner->state == tostate) {
204 rc = killpg(runner->pids[0], sig);
206 runner->state = tostate;
211 static void on_sigchld(int signum, siginfo_t *info, void *uctxt)
213 struct apprun *runner;
215 runner = runner_of_pgid(info->si_pid);
219 switch(info->si_code) {
224 runner->state = as_terminated;
229 runner->state = as_stopped;
233 runner->state = as_running;
238 /**************** handle af_launch_desc *********************/
240 static int get_jstr(struct json_object *obj, const char *key, const char **value)
243 return json_object_object_get_ex(obj, key, &data)
244 && json_object_get_type(data) == json_type_string
245 && (*value = json_object_get_string(data)) != NULL;
248 static int get_jint(struct json_object *obj, const char *key, int *value)
251 return json_object_object_get_ex(obj, key, &data)
252 && json_object_get_type(data) == json_type_int
253 && ((*value = (int)json_object_get_int(data)), 1);
256 static int fill_launch_desc(struct json_object *appli, struct af_launch_desc *desc)
261 if(!json_object_object_get_ex(appli, "public", &pub)
262 || !get_jstr(appli, "path", &desc->path)
263 || !get_jstr(appli, "id", &desc->tag)
264 || !get_jstr(appli, "content", &desc->content)
265 || !get_jstr(appli, "type", &desc->type)
266 || !get_jstr(pub, "name", &desc->name)
267 || !get_jint(pub, "width", &desc->width)
268 || !get_jint(pub, "height", &desc->height)) {
276 static const char *null = NULL;
277 desc->plugins = &null;
281 desc->home = homeappdir;
285 /**************** API handling ************************/
287 int af_run_start(struct json_object *appli)
289 static struct apprun *runner;
290 struct af_launch_desc desc;
292 sigset_t saved, blocked;
294 /* prepare to launch */
295 rc = fill_launch_desc(appli, &desc);
298 runner = createrunner(appli);
302 /* block children signals until launched */
303 sigemptyset(&blocked);
304 sigaddset(&blocked, SIGCHLD);
305 sigprocmask(SIG_BLOCK, &blocked, &saved);
308 rc = af_launch(&desc, runner->pids);
311 sigprocmask(SIG_SETMASK, &saved, NULL);
312 ERROR("can't start, af_launch failed: %m");
318 runner->state = as_running;
322 /* unblock children signal now */
323 sigprocmask(SIG_SETMASK, &saved, NULL);
327 int af_run_terminate(int runid)
329 return killrunner(runid, SIGTERM, as_terminating);
332 int af_run_stop(int runid)
334 return killrunner(runid, SIGSTOP, as_stopped);
337 int af_run_continue(int runid)
339 return killrunner(runid, SIGCONT, as_running);
342 static json_object *mkstate(struct apprun *runner)
345 struct json_object *result, *obj;
349 result = json_object_new_object();
354 obj = json_object_new_int(runner->runid);
357 json_object_object_add(result, "runid", obj); /* TODO TEST STATUS */
360 switch(runner->state) {
369 state = "terminated";
372 obj = json_object_new_string(state);
375 json_object_object_add(result, "state", obj); /* TODO TEST STATUS */
377 /* the application id */
378 rc = json_object_object_get_ex(runner->appli, "public", &obj);
380 rc = json_object_object_get_ex(obj, "id", &obj);
382 json_object_object_add(result, "id", obj); /* TODO TEST STATUS */
383 json_object_get(obj);
389 json_object_put(result);
395 struct json_object *af_run_list()
397 struct json_object *result, *obj;
398 struct apprun *runner;
401 /* creates the object */
402 result = json_object_new_array();
403 if (result == NULL) {
408 for (i = 0 ; i < ROOT_RUNNERS_COUNT ; i++) {
409 for (runner = runners_by_runid[i] ; runner ; runner = runner->next_by_runid) {
410 if (runner->state != as_terminating && runner->state != as_terminated) {
411 obj = mkstate(runner);
413 json_object_put(result);
417 json_object_array_add(result, obj);
424 struct json_object *af_run_state(int runid)
426 struct apprun *runner = getrunner(runid);
427 if (runner == NULL || runner->state == as_terminating || runner->state == as_terminated) {
431 return mkstate(runner);
434 /**************** INITIALISATION **********************/
442 struct passwd passwd, *pw;
443 struct sigaction siga;
445 /* computes the 'homeappdir' */
447 rc = getpwuid_r(me, &passwd, buf, sizeof buf, &pw);
448 if (rc || pw == NULL) {
449 errno = rc ? errno : ENOENT;
450 ERROR("getpwuid_r failed for uid=%d: %m",(int)me);
453 rc = snprintf(dir, sizeof dir, "%s/%s", passwd.pw_dir, fwk_user_app_dir);
454 if (rc >= sizeof dir) {
455 ERROR("buffer overflow in user_app_dir for uid=%d",(int)me);
458 rc = create_directory(dir, 0755, 1);
459 if (rc && errno != EEXIST) {
460 ERROR("creation of directory %s failed in user_app_dir: %m", dir);
463 homeappdir = strdup(dir);
464 if (homeappdir == NULL) {
466 ERROR("out of memory in user_app_dir for %s : %m", dir);
470 /* install signal handlers */
471 siga.sa_flags = SA_SIGINFO | SA_NOCLDWAIT;
472 sigemptyset(&siga.sa_mask);
473 sigaddset(&siga.sa_mask, SIGCHLD);
474 siga.sa_sigaction = on_sigchld;
475 sigaction(SIGCHLD, &siga, NULL);