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;
402 /* creates the object */
403 result = json_object_new_object();
404 if (result == NULL) {
409 for (i = 0 ; i < ROOT_RUNNERS_COUNT ; i++) {
410 for (runner = runners_by_runid[i] ; runner ; runner = runner->next_by_runid) {
411 if (runner->state != as_terminating && runner->state != as_terminated) {
412 obj = mkstate(runner);
414 json_object_put(result);
417 sprintf(runidstr, "%d", runner->runid);
419 json_object_object_add(result, runidstr, obj);
426 struct json_object *af_run_state(int runid)
428 struct apprun *runner = getrunner(runid);
429 if (runner == NULL || runner->state == as_terminating || runner->state == as_terminated) {
433 return mkstate(runner);
436 /**************** INITIALISATION **********************/
444 struct passwd passwd, *pw;
445 struct sigaction siga;
447 /* computes the 'homeappdir' */
449 rc = getpwuid_r(me, &passwd, buf, sizeof buf, &pw);
450 if (rc || pw == NULL) {
451 errno = rc ? errno : ENOENT;
452 ERROR("getpwuid_r failed for uid=%d: %m",(int)me);
455 rc = snprintf(dir, sizeof dir, "%s/%s", passwd.pw_dir, fwk_user_app_dir);
456 if (rc >= sizeof dir) {
457 ERROR("buffer overflow in user_app_dir for uid=%d",(int)me);
460 rc = create_directory(dir, 0755, 1);
461 if (rc && errno != EEXIST) {
462 ERROR("creation of directory %s failed in user_app_dir: %m", dir);
465 homeappdir = strdup(dir);
466 if (homeappdir == NULL) {
468 ERROR("out of memory in user_app_dir for %s : %m", dir);
472 /* install signal handlers */
473 siga.sa_flags = SA_SIGINFO | SA_NOCLDWAIT;
474 sigemptyset(&siga.sa_mask);
475 sigaddset(&siga.sa_mask, SIGCHLD);
476 siga.sa_sigaction = on_sigchld;
477 sigaction(SIGCHLD, &siga, NULL);