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));
285 assert(mode == mode_local || uri != NULL);
286 assert(uri == NULL || *uri == NULL);
288 /* prepare to launch */
289 rc = fill_launch_desc(appli, mode, &desc);
292 runner = createrunner(appli);
296 /* block children signals until launched */
297 sigemptyset(&blocked);
298 sigaddset(&blocked, SIGCHLD);
299 sigprocmask(SIG_BLOCK, &blocked, &saved);
302 rc = afm_launch(&desc, runner->pids, uri);
305 sigprocmask(SIG_SETMASK, &saved, NULL);
306 ERROR("can't start, afm_launch failed: %m");
312 runner->state = as_running;
316 /* unblock children signal now */
317 sigprocmask(SIG_SETMASK, &saved, NULL);
321 int afm_run_terminate(int runid)
323 return killrunner(runid, SIGTERM, as_terminating);
326 int afm_run_stop(int runid)
328 return killrunner(runid, SIGSTOP, as_stopped);
331 int afm_run_continue(int runid)
333 return killrunner(runid, SIGCONT, as_running);
336 static json_object *mkstate(struct apprun *runner)
339 struct json_object *result, *obj;
343 result = json_object_new_object();
348 if (!j_add_integer(result, "runid", runner->runid))
352 switch(runner->state) {
361 state = "terminated";
364 if (!j_add_string(result, "state", state))
367 /* the application id */
368 rc = json_object_object_get_ex(runner->appli, "public", &obj);
370 rc = json_object_object_get_ex(obj, "id", &obj);
372 if (!j_add(result, "id", obj))
374 json_object_get(obj);
380 json_object_put(result);
386 struct json_object *afm_run_list()
388 struct json_object *result, *obj;
389 struct apprun *runner;
392 /* creates the object */
393 result = json_object_new_array();
397 for (i = 0 ; i < ROOT_RUNNERS_COUNT ; i++) {
398 for (runner = runners_by_runid[i] ; runner ; runner = runner->next_by_runid) {
399 if (runner->state != as_terminating && runner->state != as_terminated) {
400 obj = mkstate(runner);
403 if (json_object_array_add(result, obj) == -1) {
404 json_object_put(obj);
413 json_object_put(result);
419 struct json_object *afm_run_state(int runid)
421 struct apprun *runner = getrunner(runid);
422 if (runner == NULL || runner->state == as_terminating || runner->state == as_terminated) {
426 return mkstate(runner);
429 /**************** INITIALISATION **********************/
437 struct passwd passwd, *pw;
438 struct sigaction siga;
441 rc = afm_launch_initialize();
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);