4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
8 http://www.apache.org/licenses/LICENSE-2.0
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
21 #include <sys/types.h>
31 #include "utils-dir.h"
32 #include "af-launch.h"
43 struct apprun *next_by_runid;
44 struct apprun *next_by_pgid;
46 pid_t pids[2]; /* 0: group leader, 1: slave (appli) */
51 #define ROOT_RUNNERS_COUNT 32
52 #define MAX_RUNNER_COUNT 32767
54 static struct apprun *runners_by_runid[ROOT_RUNNERS_COUNT];
55 static struct apprun *runners_by_pgid[ROOT_RUNNERS_COUNT];
56 static int runnercount = 0;
57 static int runnerid = 0;
59 static const char fwk_user_app_dir[] = FWK_USER_APP_DIR;
60 static char *homeappdir;
62 /****************** manages pgids **********************/
64 /* get a runner by its pgid */
65 static struct apprun *runner_of_pgid(pid_t pgid)
67 struct apprun *result = runners_by_pgid[(int)(pgid & (ROOT_RUNNERS_COUNT - 1))];
68 while (result && result->pids[0] != pgid)
69 result = result->next_by_pgid;
73 /* insert a runner for its pgid */
74 static void pgid_insert(struct apprun *runner)
76 struct apprun **prev = &runners_by_runid[(int)(runner->pids[0] & (ROOT_RUNNERS_COUNT - 1))];
77 runner->next_by_pgid = *prev;
81 /* remove a runner for its pgid */
82 static void pgid_remove(struct apprun *runner)
84 struct apprun **prev = &runners_by_runid[(int)(runner->pids[0] & (ROOT_RUNNERS_COUNT - 1))];
85 runner->next_by_pgid = *prev;
89 /****************** manages pids **********************/
91 /* get a runner by its pid */
92 static struct apprun *runner_of_pid(pid_t pid)
94 /* try avoiding system call */
95 struct apprun *result = runner_of_pgid(pid);
97 result = runner_of_pgid(getpgid(pid));
98 if (result && result->pids[1] != pid)
104 /****************** manages runners (by runid) **********************/
106 /* get a runner by its runid */
107 static struct apprun *getrunner(int runid)
109 struct apprun *result = runners_by_runid[runid & (ROOT_RUNNERS_COUNT - 1)];
110 while (result && result->runid != runid)
111 result = result->next_by_runid;
115 /* free an existing runner */
116 static void freerunner(struct apprun *runner)
118 struct apprun **prev = &runners_by_runid[runner->runid & (ROOT_RUNNERS_COUNT - 1)];
120 while(*prev != runner) {
121 prev = &(*prev)->next_by_runid;
124 *prev = runner->next_by_runid;
125 json_object_put(runner->appli);
130 /* create a new runner */
131 static struct apprun *createrunner(json_object *appli)
133 struct apprun *result;
134 struct apprun **prev;
136 if (runnercount >= MAX_RUNNER_COUNT) {
142 if (runnerid > MAX_RUNNER_COUNT)
144 } while(getrunner(runnerid));
145 result = calloc(1, sizeof * result);
149 prev = &runners_by_runid[runnerid & (ROOT_RUNNERS_COUNT - 1)];
150 result->next_by_runid = *prev;
151 result->next_by_pgid = NULL;
152 result->runid = runnerid;
153 result->pids[0] = result->pids[1] = 0;
154 result->state = as_starting;
155 result->appli = json_object_get(appli);
162 /**************** signaling ************************/
164 static void started(int runid)
168 static void stopped(int runid)
172 static void continued(int runid)
176 static void terminated(int runid)
180 static void removed(int runid)
184 /**************** running ************************/
186 static int killrunner(int runid, int sig, enum appstate tostate)
189 struct apprun *runner = getrunner(runid);
190 if (runner == NULL) {
194 else if (runner->state != as_running && runner->state != as_stopped) {
198 else if (runner->state == tostate) {
202 rc = killpg(runner->pids[0], sig);
204 runner->state = tostate;
209 static void on_sigchld(int signum, siginfo_t *info, void *uctxt)
211 struct apprun *runner;
213 runner = runner_of_pgid(info->si_pid);
217 switch(info->si_code) {
222 runner->state = as_terminated;
227 runner->state = as_stopped;
231 runner->state = as_running;
236 /**************** handle af_launch_desc *********************/
238 static int get_jstr(struct json_object *obj, const char *key, const char **value)
241 return json_object_object_get_ex(obj, key, &data)
242 && json_object_get_type(data) == json_type_string
243 && (*value = json_object_get_string(data)) != NULL;
246 static int get_jint(struct json_object *obj, const char *key, int *value)
249 return json_object_object_get_ex(obj, key, &data)
250 && json_object_get_type(data) == json_type_int
251 && ((*value = (int)json_object_get_int(data)), 1);
254 static int fill_launch_desc(struct json_object *appli, struct af_launch_desc *desc)
259 if(!json_object_object_get_ex(appli, "public", &pub)
260 || !get_jstr(appli, "path", &desc->path)
261 || !get_jstr(appli, "id", &desc->tag)
262 || !get_jstr(appli, "content", &desc->content)
263 || !get_jstr(appli, "type", &desc->type)
264 || !get_jstr(pub, "name", &desc->name)
265 || !get_jint(pub, "width", &desc->width)
266 || !get_jint(pub, "height", &desc->height)) {
274 static const char *null = NULL;
275 desc->plugins = &null;
279 desc->home = homeappdir;
283 /**************** API handling ************************/
285 int af_run_start(struct json_object *appli)
287 static struct apprun *runner;
288 struct af_launch_desc desc;
290 sigset_t saved, blocked;
292 /* prepare to launch */
293 rc = fill_launch_desc(appli, &desc);
296 runner = createrunner(appli);
300 /* block children signals until launched */
301 sigemptyset(&blocked);
302 sigaddset(&blocked, SIGCHLD);
303 sigprocmask(SIG_BLOCK, &blocked, &saved);
306 rc = af_launch(&desc, runner->pids);
309 sigprocmask(SIG_SETMASK, &saved, NULL);
310 ERROR("can't start, af_launch failed: %m");
316 runner->state = as_running;
319 /* unblock children signal now */
320 sigprocmask(SIG_SETMASK, &saved, NULL);
324 int af_run_terminate(int runid)
326 return killrunner(runid, SIGTERM, as_terminating);
329 int af_run_stop(int runid)
331 return killrunner(runid, SIGSTOP, as_stopped);
334 int af_run_continue(int runid)
336 return killrunner(runid, SIGCONT, as_running);
339 static json_object *mkstate(struct apprun *runner, const char **runidstr)
342 struct json_object *result, *obj, *runid;
346 result = json_object_new_object();
351 runid = json_object_new_int(runner->runid);
354 json_object_object_add(result, "runid", obj); /* TODO TEST STATUS */
357 switch(runner->state) {
366 state = "terminated";
369 obj = json_object_new_string(state);
372 json_object_object_add(result, "state", obj); /* TODO TEST STATUS */
374 /* the application id */
375 rc = json_object_object_get_ex(runner->appli, "public", &obj);
377 rc = json_object_object_get_ex(obj, "id", &obj);
379 json_object_object_add(result, "id", obj); /* TODO TEST STATUS */
380 json_object_get(obj);
384 *runidstr = json_object_get_string(runid);
388 json_object_put(result);
394 struct json_object *af_run_list()
396 struct json_object *result, *obj;
397 struct apprun *runner;
398 const char *runidstr;
401 /* creates the object */
402 result = json_object_new_object();
403 if (result == NULL) {
408 for (i = 0 ; i < ROOT_RUNNERS_COUNT ; i++) {
409 for (runner = runners_by_runid[i] ; runner ; runner = runner->next_by_runid) {
410 if (runner->state != as_terminating && runner->state != as_terminated) {
411 obj = mkstate(runner, &runidstr);
413 json_object_put(result);
417 json_object_object_add(result, runidstr, obj);
424 struct json_object *af_run_state(int runid)
426 struct apprun *runner = getrunner(runid);
427 if (runner == NULL || runner->state == as_terminating || runner->state == as_terminated) {
431 return mkstate(runner, NULL);
434 /**************** INITIALISATION **********************/
442 struct passwd passwd, *pw;
443 struct sigaction siga;
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);