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, Universitaetstrasse 6, 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 28extern char **environ; 29 30static 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 53static void set_local_bindings(void) 54{ 55 ram_alloc_set(NULL); 56} 57 58 59struct 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*/ 77static 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 130void 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 207void 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 267void 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 395void 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} 474