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