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 **********************/
70 /* get a runner by its pgid */
71 static struct apprun *runner_of_pgid(pid_t pgid)
73 struct apprun *result = runners_by_pgid[(int)(pgid & (ROOT_RUNNERS_COUNT - 1))];
74 while (result && result->pids[0] != pgid)
75 result = result->next_by_pgid;
80 /* insert a runner for its pgid */
81 static void pgid_insert(struct apprun *runner)
83 struct apprun **prev = &runners_by_runid[(int)(runner->pids[0] & (ROOT_RUNNERS_COUNT - 1))];
84 runner->next_by_pgid = *prev;
88 /* remove a runner for its pgid */
89 static void pgid_remove(struct apprun *runner)
91 struct apprun **prev = &runners_by_runid[(int)(runner->pids[0] & (ROOT_RUNNERS_COUNT - 1))];
92 runner->next_by_pgid = *prev;
96 /****************** manages pids **********************/
98 /* get a runner by its pid */
99 static struct apprun *runner_of_pid(pid_t pid)
102 struct apprun *result;
104 for (i = 0 ; i < ROOT_RUNNERS_COUNT ; i++)
105 for (result = runners_by_pgid[i] ; result != NULL ; result = result->next_by_pgid)
106 if (result->pids[0] == pid || result->pids[1] == pid)
111 /****************** manages runners (by runid) **********************/
113 /* get a runner by its runid */
114 static struct apprun *getrunner(int runid)
116 struct apprun *result = runners_by_runid[runid & (ROOT_RUNNERS_COUNT - 1)];
117 while (result && result->runid != runid)
118 result = result->next_by_runid;
122 /* free an existing runner */
123 static void freerunner(struct apprun *runner)
125 struct apprun **prev = &runners_by_runid[runner->runid & (ROOT_RUNNERS_COUNT - 1)];
127 while(*prev != runner) {
128 prev = &(*prev)->next_by_runid;
131 *prev = runner->next_by_runid;
132 json_object_put(runner->appli);
137 /* create a new runner */
138 static struct apprun *createrunner(json_object *appli)
140 struct apprun *result;
141 struct apprun **prev;
143 if (runnercount >= MAX_RUNNER_COUNT) {
149 if (runnerid > MAX_RUNNER_COUNT)
151 } while(getrunner(runnerid));
152 result = calloc(1, sizeof * result);
156 prev = &runners_by_runid[runnerid & (ROOT_RUNNERS_COUNT - 1)];
157 result->next_by_runid = *prev;
158 result->next_by_pgid = NULL;
159 result->runid = runnerid;
160 result->pids[0] = result->pids[1] = 0;
161 result->state = as_starting;
162 result->appli = json_object_get(appli);
169 /**************** signaling ************************/
171 static void started(int runid)
175 static void stopped(int runid)
179 static void continued(int runid)
183 static void terminated(int runid)
187 static void removed(int runid)
191 /**************** running ************************/
193 static int killrunner(int runid, int sig, enum appstate tostate)
196 struct apprun *runner = getrunner(runid);
197 if (runner == NULL) {
201 else if (runner->state != as_running && runner->state != as_stopped) {
205 else if (runner->state == tostate) {
209 rc = killpg(runner->pids[0], sig);
211 runner->state = tostate;
216 static void on_sigchld(int signum, siginfo_t *info, void *uctxt)
218 struct apprun *runner;
220 runner = runner_of_pid(info->si_pid);
224 switch(info->si_code) {
229 runner->state = as_terminated;
231 killpg(runner->pids[0], SIGKILL);
235 runner->state = as_stopped;
239 runner->state = as_running;
244 /**************** handle afm_launch_desc *********************/
246 static int fill_launch_desc(struct json_object *appli, enum afm_launch_mode mode, struct afm_launch_desc *desc)
250 assert(launch_mode_is_valid(mode));
253 if(!j_read_object_at(appli, "public", &pub)
254 || !j_read_string_at(appli, "path", &desc->path)
255 || !j_read_string_at(appli, "id", &desc->tag)
256 || !j_read_string_at(appli, "content", &desc->content)
257 || !j_read_string_at(appli, "type", &desc->type)
258 || !j_read_string_at(pub, "name", &desc->name)
259 || !j_read_integer_at(pub, "width", &desc->width)
260 || !j_read_integer_at(pub, "height", &desc->height)) {
268 static const char *null = NULL;
269 desc->plugins = &null;
273 desc->home = homeappdir;
278 /**************** API handling ************************/
280 int afm_run_start(struct json_object *appli, enum afm_launch_mode mode, char **uri)
282 static struct apprun *runner;
283 struct afm_launch_desc desc;
285 sigset_t saved, blocked;
287 assert(launch_mode_is_valid(mode));
288 assert(mode == mode_local || uri != NULL);
289 assert(uri == NULL || *uri == NULL);
291 /* prepare to launch */
292 rc = fill_launch_desc(appli, mode, &desc);
295 runner = createrunner(appli);
299 /* block children signals until launched */
300 sigemptyset(&blocked);
301 sigaddset(&blocked, SIGCHLD);
302 sigprocmask(SIG_BLOCK, &blocked, &saved);
305 rc = afm_launch(&desc, runner->pids, uri);
308 sigprocmask(SIG_SETMASK, &saved, NULL);
309 ERROR("can't start, afm_launch failed: %m");
315 runner->state = as_running;
319 /* unblock children signal now */
320 sigprocmask(SIG_SETMASK, &saved, NULL);
324 int afm_run_terminate(int runid)
326 return killrunner(runid, SIGTERM, as_terminating);
329 int afm_run_stop(int runid)
331 return killrunner(runid, SIGSTOP, as_stopped);
334 int afm_run_continue(int runid)
336 return killrunner(runid, SIGCONT, as_running);
339 static json_object *mkstate(struct apprun *runner)
342 struct json_object *result, *obj;
346 result = json_object_new_object();
351 if (!j_add_integer(result, "runid", runner->runid))
355 switch(runner->state) {
364 state = "terminated";
367 if (!j_add_string(result, "state", state))
370 /* the application id */
371 rc = json_object_object_get_ex(runner->appli, "public", &obj);
373 rc = json_object_object_get_ex(obj, "id", &obj);
375 if (!j_add(result, "id", obj))
377 json_object_get(obj);
383 json_object_put(result);
389 struct json_object *afm_run_list()
391 struct json_object *result, *obj;
392 struct apprun *runner;
395 /* creates the object */
396 result = json_object_new_array();
400 for (i = 0 ; i < ROOT_RUNNERS_COUNT ; i++) {
401 for (runner = runners_by_runid[i] ; runner ; runner = runner->next_by_runid) {
402 if (runner->state != as_terminating && runner->state != as_terminated) {
403 obj = mkstate(runner);
406 if (json_object_array_add(result, obj) == -1) {
407 json_object_put(obj);
416 json_object_put(result);
422 struct json_object *afm_run_state(int runid)
424 struct apprun *runner = getrunner(runid);
425 if (runner == NULL || runner->state == as_terminating || runner->state == as_terminated) {
429 return mkstate(runner);
432 /**************** INITIALISATION **********************/
440 struct passwd passwd, *pw;
441 struct sigaction siga;
444 rc = afm_launch_initialize();
448 /* computes the 'homeappdir' */
450 rc = getpwuid_r(me, &passwd, buf, sizeof buf, &pw);
451 if (rc || pw == NULL) {
452 errno = rc ? errno : ENOENT;
453 ERROR("getpwuid_r failed for uid=%d: %m",(int)me);
456 rc = snprintf(dir, sizeof dir, "%s/%s", passwd.pw_dir, fwk_user_app_dir);
457 if (rc >= sizeof dir) {
458 ERROR("buffer overflow in user_app_dir for uid=%d",(int)me);
461 rc = create_directory(dir, 0755, 1);
462 if (rc && errno != EEXIST) {
463 ERROR("creation of directory %s failed in user_app_dir: %m", dir);
466 homeappdir = strdup(dir);
467 if (homeappdir == NULL) {
469 ERROR("out of memory in user_app_dir for %s : %m", dir);
473 /* install signal handlers */
474 siga.sa_flags = SA_SIGINFO | SA_NOCLDWAIT;
475 sigemptyset(&siga.sa_mask);
476 sigaddset(&siga.sa_mask, SIGCHLD);
477 siga.sa_sigaction = on_sigchld;
478 sigaction(SIGCHLD, &siga, NULL);