proc_mgmt: merged proc management client with spawnd client
[barrelfish] / usr / startd / spawn.c
1 /**
2  * \file
3  * \brief startd spawn functions
4  */
5
6 /*
7  * Copyright (c) 2010-2011, ETH Zurich.
8  * All rights reserved.
9  *
10  * This file is distributed under the terms in the attached LICENSE file.
11  * If you do not find this file, copies can be found by writing to:
12  * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
13  */
14
15 #define _USE_XOPEN /* for strdup() in string.h */
16 #include <string.h>
17 #include <stdio.h>
18
19
20 #include <barrelfish/barrelfish.h>
21
22 #include <barrelfish/spawn_client.h>
23 #include <spawndomain/spawndomain.h>
24 #include <dist/barrier.h>
25
26 #include "internal.h"
27
28 extern char **environ;
29
30 static const char *get_shortname(const char *start, const char *nameend,
31                                  size_t *namelen)
32 {
33
34     // find the short name by searching back for the last / before the args
35     const char *shortname = nameend;
36     while (shortname >= start && *shortname != '/') {
37         shortname--;
38     }
39     if (shortname != start) {
40         shortname++;
41     }
42
43     // where's the end of the basename? (ie. ignoring beehive's | suffix)
44     const char *basenameend = memchr(shortname, '|', nameend - shortname);
45     if (basenameend == NULL) {
46         basenameend = nameend;
47     }
48
49     *namelen = basenameend - shortname;
50     return shortname;
51 }
52
53 static void set_local_bindings(void)
54 {
55     ram_alloc_set(NULL);
56 }
57
58
59 struct spawn_info {
60     int argc;
61     char *argv[MAX_CMDLINE_ARGS + 1];
62     char *name;
63     char *shortname;
64     size_t shortnamelen;
65     char *cmdargs;
66 };
67
68
69 /*
70    read the next line of the bootmodule, and return info about what to
71    spawn in *si
72    return:
73    1: line read succesfully
74    0: end of file reached
75    -1: error
76 */
77 static int prepare_spawn(size_t *bmpos, struct spawn_info *si)
78 {
79     assert(bmpos != NULL);
80     assert(si != NULL);
81
82     const char *bootmodules = gbootmodules;
83
84     // find the start/end of the next line
85     const char *start = &bootmodules[*bmpos];
86     const char *end = strchr(start, '\n');
87     if (end == NULL) {
88         return 0;
89     } else {
90         *bmpos = end - bootmodules + 1;
91     }
92
93     // ignore arguments for name comparison
94     const char *args = memchr(start, ' ', end - start);
95
96     // where's the end of the full name?
97     const char *nameend = args == NULL ? end : args;
98
99     si->shortname = (char *)get_shortname(start, nameend, &si->shortnamelen);
100
101     si->cmdargs = malloc(end - si->shortname + 1);
102     if (si->cmdargs == NULL) {
103         return -1;
104     }
105     si->name = malloc(nameend - start + 1);
106     if (si->name == NULL) {
107         free(si->cmdargs);
108         return -1;
109     }
110
111     /* Get the command line arguments of the domain: args plus shortname */
112     memcpy(si->cmdargs, si->shortname, end - si->shortname);
113     si->cmdargs[end - si->shortname] = '\0';
114     si->argc = spawn_tokenize_cmdargs(si->cmdargs, si->argv,
115                                       ARRAY_LENGTH(si->argv));
116     if (si->argc >= MAX_CMDLINE_ARGS) {
117         free(si->cmdargs);
118         free(si->name);
119         return -1;
120     }
121
122     /* grab a copy of the full name as a separate string */
123     memcpy(si->name, start, nameend - start);
124     si->name[nameend - start] = '\0';
125
126     return 1;
127 }
128
129
130 void spawn_dist_domains(void)
131 {
132     struct spawn_info si;
133     size_t bmpos = 0;
134     errval_t err;
135     int r;
136
137     coreid_t my_coreid = disp_get_core_id();
138
139     while (true) {
140
141         r = prepare_spawn(&bmpos, &si);
142         if (r == 0) {
143             return;
144         } else if (r == -1) {
145             DEBUG_ERR(STARTD_ERR_BOOTMODULES,
146                       "failed to read bootmodules entry");
147         }
148
149         /* Only spawn special dist-serv modules */
150         if (si.argc >= 2 && strcmp(si.argv[1], "dist-serv") == 0) {
151
152             coreid_t coreid;
153             int extra_args;
154
155             // get core id
156             if (si.argc >= 3 && strncmp(si.argv[2], "core=", 5) == 0) {
157
158                 char *p = strchr(si.argv[2], '=');
159                 assert(p != NULL);
160                 coreid = strtol(p + 1, NULL, 10);
161                 extra_args = 2;
162
163             } else {
164                 coreid = my_coreid;
165                 extra_args = 1;
166             }
167
168             // discard 'dist-serv' and 'core=x' argument
169             for (int i = 1; i <= si.argc - extra_args; i++) {
170                 si.argv[i] = si.argv[i+extra_args];
171             }
172             si.argc--;
173
174             debug_printf("starting dist-serv %s on core %d\n", si.name, coreid);
175
176             struct capref new_domain;
177             err = spawn_program(coreid, si.name, si.argv, environ,
178                                 0, &new_domain);
179             if (err_is_fail(err)) {
180                 DEBUG_ERR(err, "spawn of %s failed", si.name);
181                 continue;
182             }
183
184             char c = si.shortname[si.shortnamelen];
185             si.shortname[si.shortnamelen] = '\0';
186
187             // wait until fully started
188             err = nsb_wait_ready(si.shortname);
189             if (err_is_fail(err)) {
190                 DEBUG_ERR(err, "nsb_wait_ready on %s failed", si.shortname);
191             }
192
193             si.shortname[si.shortnamelen] = c;
194
195             // HACK:  make sure we use the local versions of a service if
196             // it was started. Really there needs to be a mechanism for that
197             // service to signal us and others to do this once it has started
198             // up.
199             set_local_bindings();
200         }
201
202         free(si.cmdargs);
203         free(si.name);
204     }
205 }
206
207 void spawn_arrakis_domains(void)
208 {
209     struct spawn_info si;
210     size_t bmpos = 0;
211     errval_t err;
212     int r;
213
214     coreid_t my_coreid = disp_get_core_id();
215
216     while (true) {
217
218         r = prepare_spawn(&bmpos, &si);
219         if (r == 0) {
220             return;
221         } else if (r == -1) {
222             DEBUG_ERR(STARTD_ERR_BOOTMODULES,
223                       "failed to read bootmodules entry");
224         }
225
226         /* Only spawn special arrakis modules */
227         if (si.argc >= 2 && strcmp(si.argv[1], "arrakis") == 0) {
228
229             coreid_t coreid;
230             int extra_args;
231
232             // get core id
233             if (si.argc >= 3 && strncmp(si.argv[2], "core=", 5) == 0) {
234
235                 char *p = strchr(si.argv[2], '=');
236                 assert(p != NULL);
237                 coreid = strtol(p + 1, NULL, 10);
238                 extra_args = 2;
239
240             } else {
241                 coreid = my_coreid;
242                 extra_args = 1;
243             }
244
245             // discard 'dist-serv' and 'core=x' argument
246             for (int i = 1; i <= si.argc - extra_args; i++) {
247                 si.argv[i] = si.argv[i+extra_args];
248             }
249             si.argc--;
250
251             debug_printf("starting arrakis domain %s on core %d\n", si.name, coreid);
252
253             domainid_t new_domain;
254             err = spawn_arrakis_program(coreid, si.name, si.argv, environ,
255                                         NULL_CAP, NULL_CAP, 0, &new_domain);
256             if (err_is_fail(err)) {
257                 DEBUG_ERR(err, "spawn of %s failed", si.name);
258                 continue;
259             }
260         }
261
262         free(si.cmdargs);
263         free(si.name);
264     }
265 }
266
267 void spawn_app_domains(void)
268 {
269     struct spawn_info si;
270     size_t bmpos = 0;
271     errval_t err;
272     int r;
273
274     coreid_t my_coreid = disp_get_core_id();
275
276     while (true) {
277
278         bool spawn_here = true;
279
280         r = prepare_spawn(&bmpos, &si);
281         if (r == 0) {
282             return;
283         } else if (r == -1) {
284             DEBUG_ERR(STARTD_ERR_BOOTMODULES,
285                       "failed to read bootmodules entry");
286         }
287
288         /* Do not spawn special domains */
289         if (strncmp(si.shortname, "init", si.shortnamelen) == 0
290             || strncmp(si.shortname, "cpu", si.shortnamelen) == 0
291                 // Adding following condition for cases like "cpu_omap44xx"
292             || strncmp(si.shortname, "cpu", strlen("cpu")) == 0
293             || strncmp(si.shortname, "boot_", strlen("boot_")) == 0
294             || strncmp(si.shortname, "monitor", si.shortnamelen) == 0
295             || strncmp(si.shortname, "mem_serv", si.shortnamelen) == 0
296 #ifdef __k1om__
297             || strncmp(si.shortname, "corectrl", si.shortnamelen) == 0
298 #endif
299         ) {
300             spawn_here = false;
301         }
302
303         /* Do not spawn special boot modules, dist-serv modules
304            or nospawn modules */
305         if (si.argc >= 2 && (strcmp(si.argv[1], "boot") == 0
306                           || strcmp(si.argv[1], "dist-serv") == 0
307                           || strcmp(si.argv[1], "nospawn") == 0
308                           || strcmp(si.argv[1], "arrakis") == 0
309                           || strcmp(si.argv[1], "auto") == 0)) {
310             spawn_here = false;
311         }
312
313         if (spawn_here) {
314
315             coreid_t coreid;
316
317             uint8_t spawn_flags = 0;
318             uint8_t has_spawn_flags = 0;
319             uint8_t has_core = 0;
320             char *core_ptr = NULL;
321
322             for(int i = 1; i < si.argc && i < 3; ++i) {
323                 if(strncmp(si.argv[i], "spawnflags=", 11) == 0) {
324                     char *p = strchr(si.argv[i], '=') + 1;
325                     spawn_flags = (uint8_t)strtol(p, (char **)&p, 10);
326                     has_spawn_flags = 1;
327                 } else if (strncmp(si.argv[i], "core=", 5)== 0) {
328                     core_ptr = strchr(si.argv[i], '=') + 1;
329                     has_core = 1;
330                 } else {
331                         /* ignore */
332                 }
333             }
334
335             if (has_core || has_spawn_flags) {
336                 for (int i = 1; i < si.argc; i++) {
337                     if (has_spawn_flags && has_core) {
338                         si.argv[i] = si.argv[i+2];
339                     } else {
340                         si.argv[i] = si.argv[i+1];
341                     }
342                 }
343             }
344
345             si.argc -= (has_core + has_spawn_flags);
346
347             if (has_core) {
348                 while(*core_ptr != '\0') {
349                     int id_from = strtol(core_ptr, (char **)&core_ptr, 10);
350                     int id_to = id_from;
351                     if(*core_ptr == '-') {
352                         core_ptr++;
353                         id_to = strtol(core_ptr, (char **)&core_ptr, 10);
354                     }
355                     assert(*core_ptr == ',' || *core_ptr == '\0');
356                     if(*core_ptr != '\0') {
357                         core_ptr++;
358                     }
359
360                     /* coreid = strtol(p + 1, NULL, 10); */
361                     // discard 'core=x' argument
362                     for(int i = id_from; i <= id_to; i++) {
363                         debug_printf("starting app %s on core %d\n",
364                                      si.name, i);
365
366                         struct capref ret_domain_cap;
367                         err = spawn_program(i, si.name, si.argv, environ, 
368                                             spawn_flags, &ret_domain_cap);
369                         if (err_is_fail(err)) {
370                             DEBUG_ERR(err, "spawn of %s failed", si.name);
371                         }
372                     }
373                 }
374
375             } else {
376                 coreid = my_coreid;
377
378                 debug_printf("starting app %s on core %d\n", si.name, coreid);
379
380                 struct capref ret_domain_cap;
381                 err = spawn_program(coreid, si.name, si.argv, environ, 
382                                     spawn_flags, &ret_domain_cap);
383                 if (err_is_fail(err)) {
384                     DEBUG_ERR(err, "spawn of %s failed", si.name);
385                 }
386             }
387         }
388
389         free(si.cmdargs);
390         free(si.name);
391     }
392
393 }
394
395 void spawn_bootscript_domains(void)
396 {
397     errval_t err;
398     coreid_t my_coreid = disp_get_core_id();
399     char *argv[256], *name;
400
401     // open bootmodules file and read it in
402     FILE *f = fopen("/bootscript", "r");
403     if(f == NULL) {
404         printf("No bootscript\n");
405         return;
406     }
407     char line[1024];
408     while(fgets(line, 1024, f) != NULL) {
409         int argc;
410
411         // ignore comments (#) and empty lines
412         if (line[0] == '#' || line[0] == '\n') {
413             continue;
414         }
415
416         argv[0] = strtok(line, " \n");
417         name = argv[0];
418         for(argc = 1;; argc++) {
419             argv[argc] = strtok(NULL, " \n");
420             if(argv[argc] == NULL) {
421                 break;
422             }
423         }
424
425         // get core id
426         if (argc >= 2 && strncmp(argv[1], "core=", 5) == 0) {
427             char *p = strchr(argv[1], '=');
428             assert(p != NULL);
429
430             p++;
431             while(*p != '\0') {
432                 int id_from = strtol(p, (char **)&p, 10), id_to = id_from;
433                 if(*p == '-') {
434                     p++;
435                     id_to = strtol(p, (char **)&p, 10);
436                 }
437                 assert(*p == ',' || *p == '\0');
438                 if(*p != '\0') {
439                     p++;
440                 }
441
442                 /* coreid = strtol(p + 1, NULL, 10); */
443                 // discard 'core=x' argument
444                 for (int i = 1; i < argc; i++) {
445                     argv[i] = argv[i+1];
446                 }
447                 argc--;
448
449                 for(int i = id_from; i <= id_to; i++) {
450                     debug_printf("starting app %s on core %d\n", name, i);
451
452                     struct capref new_domain;
453                     err = spawn_program(i, name, argv, environ,
454                                         0, &new_domain);
455                     if (err_is_fail(err)) {
456                         DEBUG_ERR(err, "spawn of %s failed", name);
457                     }
458                 }
459             }
460         } else {
461             debug_printf("starting app %s on core %d\n", name, my_coreid);
462
463             struct capref new_domain;
464             err = spawn_program(my_coreid, name, argv, environ,
465                                 0, &new_domain);
466             if (err_is_fail(err)) {
467                 DEBUG_ERR(err, "spawn of %s failed", name);
468             }
469         }
470     }
471
472     fclose(f);
473 }