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 "utils-json.h"
36 #include "afm-launch.h"
47 struct apprun *next_by_runid;
48 struct apprun *next_by_pgid;
50 pid_t pids[2]; /* 0: group leader, 1: slave (appli) */
55 #define ROOT_RUNNERS_COUNT 32
56 #define MAX_RUNNER_COUNT 32767
58 static struct apprun *runners_by_runid[ROOT_RUNNERS_COUNT];
59 static struct apprun *runners_by_pgid[ROOT_RUNNERS_COUNT];
60 static int runnercount = 0;
61 static int runnerid = 0;
63 static const char fwk_user_app_dir[] = FWK_USER_APP_DIR;
64 static char *homeappdir;
66 /****************** manages pgids **********************/
68 /* get a runner by its pgid */
69 static struct apprun *runner_of_pgid(pid_t pgid)
71 struct apprun *result = runners_by_pgid[(int)(pgid & (ROOT_RUNNERS_COUNT - 1))];
72 while (result && result->pids[0] != pgid)
73 result = result->next_by_pgid;
77 /* insert a runner for its pgid */
78 static void pgid_insert(struct apprun *runner)
80 struct apprun **prev = &runners_by_runid[(int)(runner->pids[0] & (ROOT_RUNNERS_COUNT - 1))];
81 runner->next_by_pgid = *prev;
85 /* remove a runner for its pgid */
86 static void pgid_remove(struct apprun *runner)
88 struct apprun **prev = &runners_by_runid[(int)(runner->pids[0] & (ROOT_RUNNERS_COUNT - 1))];
89 runner->next_by_pgid = *prev;
93 /****************** manages pids **********************/
95 /* get a runner by its pid */
96 static struct apprun *runner_of_pid(pid_t pid)
98 /* try avoiding system call */
99 struct apprun *result = runner_of_pgid(pid);
100 if (result == NULL) {
101 result = runner_of_pgid(getpgid(pid));
102 if (result && result->pids[1] != pid)
108 /****************** manages runners (by runid) **********************/
110 /* get a runner by its runid */
111 static struct apprun *getrunner(int runid)
113 struct apprun *result = runners_by_runid[runid & (ROOT_RUNNERS_COUNT - 1)];
114 while (result && result->runid != runid)
115 result = result->next_by_runid;
119 /* free an existing runner */
120 static void freerunner(struct apprun *runner)
122 struct apprun **prev = &runners_by_runid[runner->runid & (ROOT_RUNNERS_COUNT - 1)];
124 while(*prev != runner) {
125 prev = &(*prev)->next_by_runid;
128 *prev = runner->next_by_runid;
129 json_object_put(runner->appli);
134 /* create a new runner */
135 static struct apprun *createrunner(json_object *appli)
137 struct apprun *result;
138 struct apprun **prev;
140 if (runnercount >= MAX_RUNNER_COUNT) {
146 if (runnerid > MAX_RUNNER_COUNT)
148 } while(getrunner(runnerid));
149 result = calloc(1, sizeof * result);
153 prev = &runners_by_runid[runnerid & (ROOT_RUNNERS_COUNT - 1)];
154 result->next_by_runid = *prev;
155 result->next_by_pgid = NULL;
156 result->runid = runnerid;
157 result->pids[0] = result->pids[1] = 0;
158 result->state = as_starting;
159 result->appli = json_object_get(appli);
166 /**************** signaling ************************/
168 static void started(int runid)
172 static void stopped(int runid)
176 static void continued(int runid)
180 static void terminated(int runid)
184 static void removed(int runid)
188 /**************** running ************************/
190 static int killrunner(int runid, int sig, enum appstate tostate)
193 struct apprun *runner = getrunner(runid);
194 if (runner == NULL) {
198 else if (runner->state != as_running && runner->state != as_stopped) {
202 else if (runner->state == tostate) {
206 rc = killpg(runner->pids[0], sig);
208 runner->state = tostate;
213 static void on_sigchld(int signum, siginfo_t *info, void *uctxt)
215 struct apprun *runner;
217 runner = runner_of_pgid(info->si_pid);
221 switch(info->si_code) {
226 runner->state = as_terminated;
231 runner->state = as_stopped;
235 runner->state = as_running;
240 /**************** handle afm_launch_desc *********************/
242 static int fill_launch_desc(struct json_object *appli, struct afm_launch_desc *desc)
247 if(!j_object(appli, "public", &pub)
248 || !j_string(appli, "path", &desc->path)
249 || !j_string(appli, "id", &desc->tag)
250 || !j_string(appli, "content", &desc->content)
251 || !j_string(appli, "type", &desc->type)
252 || !j_string(pub, "name", &desc->name)
253 || !j_integer(pub, "width", &desc->width)
254 || !j_integer(pub, "height", &desc->height)) {
262 static const char *null = NULL;
263 desc->plugins = &null;
267 desc->home = homeappdir;
271 /**************** API handling ************************/
273 int afm_run_start(struct json_object *appli)
275 static struct apprun *runner;
276 struct afm_launch_desc desc;
278 sigset_t saved, blocked;
280 /* prepare to launch */
281 rc = fill_launch_desc(appli, &desc);
284 runner = createrunner(appli);
288 /* block children signals until launched */
289 sigemptyset(&blocked);
290 sigaddset(&blocked, SIGCHLD);
291 sigprocmask(SIG_BLOCK, &blocked, &saved);
294 rc = afm_launch(&desc, runner->pids);
297 sigprocmask(SIG_SETMASK, &saved, NULL);
298 ERROR("can't start, afm_launch failed: %m");
304 runner->state = as_running;
308 /* unblock children signal now */
309 sigprocmask(SIG_SETMASK, &saved, NULL);
313 int afm_run_terminate(int runid)
315 return killrunner(runid, SIGTERM, as_terminating);
318 int afm_run_stop(int runid)
320 return killrunner(runid, SIGSTOP, as_stopped);
323 int afm_run_continue(int runid)
325 return killrunner(runid, SIGCONT, as_running);
328 static json_object *mkstate(struct apprun *runner)
331 struct json_object *result, *obj;
335 result = json_object_new_object();
340 if (!j_add_integer(result, "runid", runner->runid))
344 switch(runner->state) {
353 state = "terminated";
356 if (!j_add_string(result, "state", state))
359 /* the application id */
360 rc = json_object_object_get_ex(runner->appli, "public", &obj);
362 rc = json_object_object_get_ex(obj, "id", &obj);
364 if (!j_add(result, "id", obj))
366 json_object_get(obj);
372 json_object_put(result);
378 struct json_object *afm_run_list()
380 struct json_object *result, *obj;
381 struct apprun *runner;
384 /* creates the object */
385 result = json_object_new_array();
389 for (i = 0 ; i < ROOT_RUNNERS_COUNT ; i++) {
390 for (runner = runners_by_runid[i] ; runner ; runner = runner->next_by_runid) {
391 if (runner->state != as_terminating && runner->state != as_terminated) {
392 obj = mkstate(runner);
395 if (json_object_array_add(result, obj) == -1) {
396 json_object_put(obj);
405 json_object_put(result);
411 struct json_object *afm_run_state(int runid)
413 struct apprun *runner = getrunner(runid);
414 if (runner == NULL || runner->state == as_terminating || runner->state == as_terminated) {
418 return mkstate(runner);
421 /**************** INITIALISATION **********************/
429 struct passwd passwd, *pw;
430 struct sigaction siga;
432 /* computes the 'homeappdir' */
434 rc = getpwuid_r(me, &passwd, buf, sizeof buf, &pw);
435 if (rc || pw == NULL) {
436 errno = rc ? errno : ENOENT;
437 ERROR("getpwuid_r failed for uid=%d: %m",(int)me);
440 rc = snprintf(dir, sizeof dir, "%s/%s", passwd.pw_dir, fwk_user_app_dir);
441 if (rc >= sizeof dir) {
442 ERROR("buffer overflow in user_app_dir for uid=%d",(int)me);
445 rc = create_directory(dir, 0755, 1);
446 if (rc && errno != EEXIST) {
447 ERROR("creation of directory %s failed in user_app_dir: %m", dir);
450 homeappdir = strdup(dir);
451 if (homeappdir == NULL) {
453 ERROR("out of memory in user_app_dir for %s : %m", dir);
457 /* install signal handlers */
458 siga.sa_flags = SA_SIGINFO | SA_NOCLDWAIT;
459 sigemptyset(&siga.sa_mask);
460 sigaddset(&siga.sa_mask, SIGCHLD);
461 siga.sa_sigaction = on_sigchld;
462 sigaction(SIGCHLD, &siga, NULL);