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"
35 #include "afm-launch-mode.h"
36 #include "afm-launch.h"
48 struct apprun *next_by_runid;
49 struct apprun *next_by_pgid;
51 pid_t pids[2]; /* 0: group leader, 1: slave (appli) */
56 #define ROOT_RUNNERS_COUNT 32
57 #define MAX_RUNNER_COUNT 32767
59 static struct apprun *runners_by_runid[ROOT_RUNNERS_COUNT];
60 static struct apprun *runners_by_pgid[ROOT_RUNNERS_COUNT];
61 static int runnercount = 0;
62 static int runnerid = 0;
64 static const char fwk_user_app_dir[] = FWK_USER_APP_DIR;
65 static char *homeappdir;
67 /****************** manages pgids **********************/
69 /* get a runner by its pgid */
70 static struct apprun *runner_of_pgid(pid_t pgid)
72 struct apprun *result = runners_by_pgid[(int)(pgid & (ROOT_RUNNERS_COUNT - 1))];
73 while (result && result->pids[0] != pgid)
74 result = result->next_by_pgid;
78 /* insert a runner for its pgid */
79 static void pgid_insert(struct apprun *runner)
81 struct apprun **prev = &runners_by_runid[(int)(runner->pids[0] & (ROOT_RUNNERS_COUNT - 1))];
82 runner->next_by_pgid = *prev;
86 /* remove a runner for its pgid */
87 static void pgid_remove(struct apprun *runner)
89 struct apprun **prev = &runners_by_runid[(int)(runner->pids[0] & (ROOT_RUNNERS_COUNT - 1))];
90 runner->next_by_pgid = *prev;
94 /****************** manages pids **********************/
96 /* get a runner by its pid */
97 static struct apprun *runner_of_pid(pid_t pid)
99 /* try avoiding system call */
100 struct apprun *result = runner_of_pgid(pid);
101 if (result == NULL) {
102 result = runner_of_pgid(getpgid(pid));
103 if (result && result->pids[1] != pid)
109 /****************** manages runners (by runid) **********************/
111 /* get a runner by its runid */
112 static struct apprun *getrunner(int runid)
114 struct apprun *result = runners_by_runid[runid & (ROOT_RUNNERS_COUNT - 1)];
115 while (result && result->runid != runid)
116 result = result->next_by_runid;
120 /* free an existing runner */
121 static void freerunner(struct apprun *runner)
123 struct apprun **prev = &runners_by_runid[runner->runid & (ROOT_RUNNERS_COUNT - 1)];
125 while(*prev != runner) {
126 prev = &(*prev)->next_by_runid;
129 *prev = runner->next_by_runid;
130 json_object_put(runner->appli);
135 /* create a new runner */
136 static struct apprun *createrunner(json_object *appli)
138 struct apprun *result;
139 struct apprun **prev;
141 if (runnercount >= MAX_RUNNER_COUNT) {
147 if (runnerid > MAX_RUNNER_COUNT)
149 } while(getrunner(runnerid));
150 result = calloc(1, sizeof * result);
154 prev = &runners_by_runid[runnerid & (ROOT_RUNNERS_COUNT - 1)];
155 result->next_by_runid = *prev;
156 result->next_by_pgid = NULL;
157 result->runid = runnerid;
158 result->pids[0] = result->pids[1] = 0;
159 result->state = as_starting;
160 result->appli = json_object_get(appli);
167 /**************** signaling ************************/
169 static void started(int runid)
173 static void stopped(int runid)
177 static void continued(int runid)
181 static void terminated(int runid)
185 static void removed(int runid)
189 /**************** running ************************/
191 static int killrunner(int runid, int sig, enum appstate tostate)
194 struct apprun *runner = getrunner(runid);
195 if (runner == NULL) {
199 else if (runner->state != as_running && runner->state != as_stopped) {
203 else if (runner->state == tostate) {
207 rc = killpg(runner->pids[0], sig);
209 runner->state = tostate;
214 static void on_sigchld(int signum, siginfo_t *info, void *uctxt)
216 struct apprun *runner;
218 runner = runner_of_pgid(info->si_pid);
222 switch(info->si_code) {
227 runner->state = as_terminated;
232 runner->state = as_stopped;
236 runner->state = as_running;
241 /**************** handle afm_launch_desc *********************/
243 static int fill_launch_desc(struct json_object *appli, enum afm_launch_mode mode, struct afm_launch_desc *desc)
247 assert(launch_mode_is_valid(mode));
250 if(!j_read_object_at(appli, "public", &pub)
251 || !j_read_string_at(appli, "path", &desc->path)
252 || !j_read_string_at(appli, "id", &desc->tag)
253 || !j_read_string_at(appli, "content", &desc->content)
254 || !j_read_string_at(appli, "type", &desc->type)
255 || !j_read_string_at(pub, "name", &desc->name)
256 || !j_read_integer_at(pub, "width", &desc->width)
257 || !j_read_integer_at(pub, "height", &desc->height)) {
265 static const char *null = NULL;
266 desc->plugins = &null;
270 desc->home = homeappdir;
275 /**************** API handling ************************/
277 int afm_run_start(struct json_object *appli, enum afm_launch_mode mode, char **uri)
279 static struct apprun *runner;
280 struct afm_launch_desc desc;
282 sigset_t saved, blocked;
284 assert(launch_mode_is_valid(mode));
286 /* prepare to launch */
287 rc = fill_launch_desc(appli, mode, &desc);
290 runner = createrunner(appli);
294 /* block children signals until launched */
295 sigemptyset(&blocked);
296 sigaddset(&blocked, SIGCHLD);
297 sigprocmask(SIG_BLOCK, &blocked, &saved);
300 rc = afm_launch(&desc, runner->pids, uri);
303 sigprocmask(SIG_SETMASK, &saved, NULL);
304 ERROR("can't start, afm_launch failed: %m");
310 runner->state = as_running;
314 /* unblock children signal now */
315 sigprocmask(SIG_SETMASK, &saved, NULL);
319 int afm_run_terminate(int runid)
321 return killrunner(runid, SIGTERM, as_terminating);
324 int afm_run_stop(int runid)
326 return killrunner(runid, SIGSTOP, as_stopped);
329 int afm_run_continue(int runid)
331 return killrunner(runid, SIGCONT, as_running);
334 static json_object *mkstate(struct apprun *runner)
337 struct json_object *result, *obj;
341 result = json_object_new_object();
346 if (!j_add_integer(result, "runid", runner->runid))
350 switch(runner->state) {
359 state = "terminated";
362 if (!j_add_string(result, "state", state))
365 /* the application id */
366 rc = json_object_object_get_ex(runner->appli, "public", &obj);
368 rc = json_object_object_get_ex(obj, "id", &obj);
370 if (!j_add(result, "id", obj))
372 json_object_get(obj);
378 json_object_put(result);
384 struct json_object *afm_run_list()
386 struct json_object *result, *obj;
387 struct apprun *runner;
390 /* creates the object */
391 result = json_object_new_array();
395 for (i = 0 ; i < ROOT_RUNNERS_COUNT ; i++) {
396 for (runner = runners_by_runid[i] ; runner ; runner = runner->next_by_runid) {
397 if (runner->state != as_terminating && runner->state != as_terminated) {
398 obj = mkstate(runner);
401 if (json_object_array_add(result, obj) == -1) {
402 json_object_put(obj);
411 json_object_put(result);
417 struct json_object *afm_run_state(int runid)
419 struct apprun *runner = getrunner(runid);
420 if (runner == NULL || runner->state == as_terminating || runner->state == as_terminated) {
424 return mkstate(runner);
427 /**************** INITIALISATION **********************/
435 struct passwd passwd, *pw;
436 struct sigaction siga;
439 rc = afm_launch_initialize();
443 /* computes the 'homeappdir' */
445 rc = getpwuid_r(me, &passwd, buf, sizeof buf, &pw);
446 if (rc || pw == NULL) {
447 errno = rc ? errno : ENOENT;
448 ERROR("getpwuid_r failed for uid=%d: %m",(int)me);
451 rc = snprintf(dir, sizeof dir, "%s/%s", passwd.pw_dir, fwk_user_app_dir);
452 if (rc >= sizeof dir) {
453 ERROR("buffer overflow in user_app_dir for uid=%d",(int)me);
456 rc = create_directory(dir, 0755, 1);
457 if (rc && errno != EEXIST) {
458 ERROR("creation of directory %s failed in user_app_dir: %m", dir);
461 homeappdir = strdup(dir);
462 if (homeappdir == NULL) {
464 ERROR("out of memory in user_app_dir for %s : %m", dir);
468 /* install signal handlers */
469 siga.sa_flags = SA_SIGINFO | SA_NOCLDWAIT;
470 sigemptyset(&siga.sa_mask);
471 sigaddset(&siga.sa_mask, SIGCHLD);
472 siga.sa_sigaction = on_sigchld;
473 sigaction(SIGCHLD, &siga, NULL);