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 pids **********************/
69 /* get a runner by its pid */
70 static struct apprun *runner_of_pid(pid_t pid)
73 struct apprun *result;
75 for (i = 0 ; i < ROOT_RUNNERS_COUNT ; i++)
76 for (result = runners_by_pgid[i] ; result != NULL ; result = result->next_by_pgid)
77 if (result->pids[0] == pid || result->pids[1] == pid)
82 /****************** manages pgids **********************/
84 /* get a runner by its pgid */
85 static struct apprun *runner_of_pgid(pid_t pgid)
87 struct apprun *result = runners_by_pgid[(int)(pgid & (ROOT_RUNNERS_COUNT - 1))];
88 while (result && result->pids[0] != pgid)
89 result = result->next_by_pgid;
93 /* insert a runner for its pgid */
94 static void pgid_insert(struct apprun *runner)
96 struct apprun **prev = &runners_by_pgid[(int)(runner->pids[0] & (ROOT_RUNNERS_COUNT - 1))];
97 runner->next_by_pgid = *prev;
101 /* remove a runner for its pgid */
102 static void pgid_remove(struct apprun *runner)
104 struct apprun **prev = &runners_by_pgid[(int)(runner->pids[0] & (ROOT_RUNNERS_COUNT - 1))];
106 if (*prev == runner) {
107 *prev = runner->next_by_pgid;
110 prev = &(*prev)->next_by_pgid;
114 /****************** manages runners (by runid) **********************/
116 /* get a runner by its runid */
117 static struct apprun *getrunner(int runid)
119 struct apprun *result = runners_by_runid[runid & (ROOT_RUNNERS_COUNT - 1)];
120 while (result && result->runid != runid)
121 result = result->next_by_runid;
125 /* free an existing runner */
126 static void freerunner(struct apprun *runner)
128 struct apprun **prev = &runners_by_runid[runner->runid & (ROOT_RUNNERS_COUNT - 1)];
130 while(*prev != runner) {
131 prev = &(*prev)->next_by_runid;
134 *prev = runner->next_by_runid;
135 json_object_put(runner->appli);
140 /* create a new runner */
141 static struct apprun *createrunner(json_object *appli)
143 struct apprun *result;
144 struct apprun **prev;
146 if (runnercount >= MAX_RUNNER_COUNT) {
152 if (runnerid > MAX_RUNNER_COUNT)
154 } while(getrunner(runnerid));
155 result = calloc(1, sizeof * result);
159 prev = &runners_by_runid[runnerid & (ROOT_RUNNERS_COUNT - 1)];
160 result->next_by_runid = *prev;
161 result->next_by_pgid = NULL;
162 result->runid = runnerid;
163 result->pids[0] = result->pids[1] = 0;
164 result->state = as_starting;
165 result->appli = json_object_get(appli);
172 /**************** signaling ************************/
174 static void started(int runid)
178 static void stopped(int runid)
182 static void continued(int runid)
186 static void terminated(int runid)
190 static void removed(int runid)
194 /**************** running ************************/
196 static int killrunner(int runid, int sig, enum appstate tostate)
199 struct apprun *runner = getrunner(runid);
200 if (runner == NULL) {
204 else if (runner->state != as_running && runner->state != as_stopped) {
208 else if (runner->state == tostate) {
212 rc = killpg(runner->pids[0], sig);
214 runner->state = tostate;
219 static void on_sigchld(int signum, siginfo_t *info, void *uctxt)
221 struct apprun *runner;
223 runner = runner_of_pid(info->si_pid);
227 switch(info->si_code) {
232 runner->state = as_terminated;
234 killpg(runner->pids[0], SIGKILL);
238 runner->state = as_stopped;
242 runner->state = as_running;
247 /**************** handle afm_launch_desc *********************/
249 static int fill_launch_desc(struct json_object *appli, enum afm_launch_mode mode, struct afm_launch_desc *desc)
253 assert(launch_mode_is_valid(mode));
256 if(!j_read_object_at(appli, "public", &pub)
257 || !j_read_string_at(appli, "path", &desc->path)
258 || !j_read_string_at(appli, "id", &desc->tag)
259 || !j_read_string_at(appli, "content", &desc->content)
260 || !j_read_string_at(appli, "type", &desc->type)
261 || !j_read_string_at(pub, "name", &desc->name)
262 || !j_read_integer_at(pub, "width", &desc->width)
263 || !j_read_integer_at(pub, "height", &desc->height)) {
271 static const char *null = NULL;
272 desc->plugins = &null;
276 desc->home = homeappdir;
281 /**************** API handling ************************/
283 int afm_run_start(struct json_object *appli, enum afm_launch_mode mode, char **uri)
285 static struct apprun *runner;
286 struct afm_launch_desc desc;
288 sigset_t saved, blocked;
290 assert(launch_mode_is_valid(mode));
291 assert(mode == mode_local || uri != NULL);
292 assert(uri == NULL || *uri == NULL);
294 /* prepare to launch */
295 rc = fill_launch_desc(appli, mode, &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 = afm_launch(&desc, runner->pids, uri);
311 sigprocmask(SIG_SETMASK, &saved, NULL);
312 ERROR("can't start, afm_launch failed: %m");
318 runner->state = as_running;
322 /* unblock children signal now */
323 sigprocmask(SIG_SETMASK, &saved, NULL);
327 int afm_run_terminate(int runid)
329 return killrunner(runid, SIGTERM, as_terminating);
332 int afm_run_stop(int runid)
334 return killrunner(runid, SIGSTOP, as_stopped);
337 int afm_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 if (!j_add_integer(result, "runid", runner->runid))
358 switch(runner->state) {
367 state = "terminated";
370 if (!j_add_string(result, "state", state))
373 /* the application id */
374 rc = json_object_object_get_ex(runner->appli, "public", &obj);
376 rc = json_object_object_get_ex(obj, "id", &obj);
378 if (!j_add(result, "id", obj))
380 json_object_get(obj);
386 json_object_put(result);
392 struct json_object *afm_run_list()
394 struct json_object *result, *obj;
395 struct apprun *runner;
398 /* creates the object */
399 result = json_object_new_array();
403 for (i = 0 ; i < ROOT_RUNNERS_COUNT ; i++) {
404 for (runner = runners_by_runid[i] ; runner ; runner = runner->next_by_runid) {
405 if (runner->state != as_terminating && runner->state != as_terminated) {
406 obj = mkstate(runner);
409 if (json_object_array_add(result, obj) == -1) {
410 json_object_put(obj);
419 json_object_put(result);
425 struct json_object *afm_run_state(int runid)
427 struct apprun *runner = getrunner(runid);
428 if (runner == NULL || runner->state == as_terminating || runner->state == as_terminated) {
432 return mkstate(runner);
435 /**************** INITIALISATION **********************/
443 struct passwd passwd, *pw;
444 struct sigaction siga;
447 rc = afm_launch_initialize();
451 /* computes the 'homeappdir' */
453 rc = getpwuid_r(me, &passwd, buf, sizeof buf, &pw);
454 if (rc || pw == NULL) {
455 errno = rc ? errno : ENOENT;
456 ERROR("getpwuid_r failed for uid=%d: %m",(int)me);
459 rc = snprintf(dir, sizeof dir, "%s/%s", passwd.pw_dir, fwk_user_app_dir);
460 if (rc >= sizeof dir) {
461 ERROR("buffer overflow in user_app_dir for uid=%d",(int)me);
464 rc = create_directory(dir, 0755, 1);
465 if (rc && errno != EEXIST) {
466 ERROR("creation of directory %s failed in user_app_dir: %m", dir);
469 homeappdir = strdup(dir);
470 if (homeappdir == NULL) {
472 ERROR("out of memory in user_app_dir for %s : %m", dir);
476 /* install signal handlers */
477 siga.sa_flags = SA_SIGINFO | SA_NOCLDWAIT;
478 sigemptyset(&siga.sa_mask);
479 sigaddset(&siga.sa_mask, SIGCHLD);
480 siga.sa_sigaction = on_sigchld;
481 sigaction(SIGCHLD, &siga, NULL);