3 * \brief Client for interacting with the process management server.
7 * Copyright (c) 2017, ETH Zurich.
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.
15 #include <barrelfish/barrelfish.h>
16 #include <barrelfish/nameservice_client.h>
17 #include <barrelfish/spawn_client.h>
18 #include <if/octopus_defs.h>
19 #include <if/proc_mgmt_defs.h>
20 #include <if/arrakis_defs.h>
21 #include <if/monitor_defs.h>
22 #include <if/spawn_defs.h>
23 #include <vfs/vfs_path.h>
25 // For spawn_program_on_all_cores
26 #include <octopus/getset.h> // for oct_read TODO
27 #include <octopus/trigger.h> // for NOP_TRIGGER
30 struct proc_mgmt_bind_retst {
32 struct proc_mgmt_binding *b;
36 struct spawn_bind_retst {
38 struct spawn_binding *b;
42 struct arrakis_bind_retst {
44 struct arrakis_binding *b;
48 extern char **environ;
50 static void spawn_bind_cont(void *st, errval_t err, struct spawn_binding *b)
52 struct spawn_bind_retst *retst = st;
53 assert(retst != NULL);
54 assert(!retst->present);
57 retst->present = true;
60 static void arrakis_bind_cont(void *st, errval_t err, struct arrakis_binding *b)
62 struct arrakis_bind_retst *retst = st;
63 assert(retst != NULL);
64 assert(!retst->present);
67 retst->present = true;
70 static struct spawn_binding *spawn_b = NULL;
72 static errval_t bind_client(coreid_t coreid)
74 struct spawn_binding *cl;
75 errval_t err = SYS_ERR_OK;
77 // do we have a spawn client connection for this core?
78 assert(coreid < MAX_CPUS);
79 cl = get_spawn_binding(coreid);
82 snprintf(namebuf, sizeof(namebuf), "spawn.%u", coreid);
83 namebuf[sizeof(namebuf) - 1] = '\0';
86 err = nameservice_blocking_lookup(namebuf, &iref);
87 if (err_is_fail(err)) {
88 //DEBUG_ERR(err, "spawn daemon on core %u not found\n", coreid);
93 struct spawn_bind_retst bindst = { .present = false };
94 err = spawn_bind(iref, spawn_bind_cont, &bindst, get_default_waitset(),
95 IDC_BIND_FLAGS_DEFAULT);
96 if (err_is_fail(err)) {
97 DEBUG_ERR(err, "spawn_bind failed");
101 // XXX: block for bind completion
102 while (!bindst.present) {
103 messages_wait_and_handle_next();
106 if (err_is_fail(bindst.err)) {
112 spawn_rpc_client_init(bindst.b);
113 set_spawn_binding(coreid, bindst.b);
119 errval_t spawn_bind_iref(iref_t iref, struct spawn_binding **ret_client)
121 assert(ret_client != NULL);
123 struct spawn_bind_retst bindst = { .present = false };
124 errval_t err = spawn_bind(iref, spawn_bind_cont, &bindst,
125 get_default_waitset(), IDC_BIND_FLAGS_DEFAULT);
126 if (err_is_fail(err)) {
127 DEBUG_ERR(err, "spawn_bind failed");
131 // XXX: block for bind completion
132 while (!bindst.present) {
133 messages_wait_and_handle_next();
136 if (err_is_fail(bindst.err)) {
140 spawn_rpc_client_init(bindst.b);
141 *ret_client = bindst.b;
142 // set_spawn_binding(coreid, bindst.b);
148 static void error_handler(struct proc_mgmt_binding *b, errval_t err)
150 #if defined(__x86_64__) || defined(__i386__)
151 debug_printf("%p \n", __builtin_return_address(0));
153 debug_err(__FILE__, __func__, __LINE__, err,
154 "asynchronous error in proc_mgmt binding");
158 static void proc_mgmt_bind_cont(void *st, errval_t err,
159 struct proc_mgmt_binding *b)
161 struct proc_mgmt_bind_retst *retst = (struct proc_mgmt_bind_retst*) st;
162 assert(retst != NULL);
163 assert(!retst->present);
166 retst->present = true;
170 static void proc_mgmt_accept_recv_handler(void *arg)
172 struct proc_mgmt_lmp_binding *b = arg;
173 struct lmp_recv_msg msg = LMP_RECV_MSG_INIT;
177 // try to retrieve a message from the channel
178 err = lmp_chan_recv(&b->chan, &msg, &cap);
179 if (err_is_fail(err)) {
180 if (err_no(err) == LIB_ERR_NO_LMP_MSG) {
181 // nothing there, re-register
182 struct event_closure recv_handler = {
183 .handler = proc_mgmt_accept_recv_handler,
186 err = lmp_chan_register_recv(&b->chan, b->b.waitset, recv_handler);
187 b->b.error_handler(&b->b, err_push(err, LIB_ERR_CHAN_REGISTER_RECV));
189 // real error, report to user
190 b->b.error_handler(&b->b, err_push(err, LIB_ERR_LMP_CHAN_RECV));
195 // TODO(razvan): LMP_PROC_MGMT_ACCEPT ?
196 assert(b->chan.connstate == LMP_MONITOR_ACCEPT);
197 assert(!capref_is_null(cap));
198 b->chan.remote_cap = cap;
199 b->chan.connstate = LMP_CONNECTED;
201 /* allocate a new receive slot */
202 err = lmp_chan_alloc_recv_slot(&b->chan);
203 if (err_is_fail(err)) {
204 // XXX: report the error, but continue
205 b->b.error_handler(&b->b, err_push(err, LIB_ERR_LMP_ALLOC_RECV_SLOT));
208 /* Run the RX handler; has a side-effect of registering for receive events */
209 proc_mgmt_lmp_rx_handler(b);
212 static errval_t init_lmp_binding(struct proc_mgmt_lmp_binding *lmpb,
218 proc_mgmt_lmp_init(lmpb, ws);
220 /* allocate a cap slot for the new endpoint cap */
221 err = slot_alloc(&lmpb->chan.local_cap);
222 if (err_is_fail(err)) {
223 return err_push(err, LIB_ERR_SLOT_ALLOC);
226 /* allocate a local endpoint */
227 err = lmp_endpoint_create_in_slot(buflen_words, lmpb->chan.local_cap,
228 &lmpb->chan.endpoint);
229 if (err_is_fail(err)) {
230 // TODO(razvan): Free cap slot.
231 return err_push(err, LIB_ERR_ENDPOINT_CREATE);
234 /* allocate an initial receive slot */
235 err = lmp_chan_alloc_recv_slot(&lmpb->chan);
236 if (err_is_fail(err)) {
240 /* setup error handler */
241 lmpb->b.error_handler = error_handler;
243 /* setup initial receive handlers */
244 // TODO(razvan): Don't think this is needed, but dunno for sure yet.
245 // lmpb->b.rx_vtbl = monitor_rx_vtbl;
248 lmpb->b.change_waitset(&lmpb->b, lmpb->b.waitset);
253 * \brief Accept a new LMP binding to a proc mgmt client.
255 * Should only be used in the process manager.
257 * \param lmpb Storage for binding state
258 * \param ws Waitset for handling incoming messages
259 * \param buflen_words Size of incoming buffer, in number of words
261 errval_t proc_mgmt_client_lmp_accept(struct proc_mgmt_lmp_binding *lmpb,
263 size_t lmp_buflen_words)
265 errval_t err = init_lmp_binding(lmpb, ws, lmp_buflen_words);
266 if (err_is_fail(err)) {
270 lmpb->chan.connstate = LMP_MONITOR_ACCEPT; // TODO(razvan): LMP_PROC_MGMT_ACCEPT?
271 lmpb->chan.remote_cap = NULL_CAP; // will be sent to us by the client
273 /* Register for receive notification on our special handler */
274 struct event_closure receive_handler = {
275 .handler = proc_mgmt_accept_recv_handler,
278 err = lmp_chan_register_recv(&lmpb->chan, ws, receive_handler);
279 if (err_is_fail(err)) {
280 return err; // TODO(razvan): cleanup?
288 * \brief Initiate a new LMP binding to the process manager
290 * To be used by the monitor for setting up the privileged channel used for
292 * Requires an explicit remote endpoint cap allocated by the process manager.
294 * \param lmpb Storage for binding state
295 * \param ep Remote endpoint of the process manager
296 * \param ws Waitset for handling incoming messages
297 * \param cont Continuation for when binding completes or fails
298 * \param st State passed to continuation function
299 * \param buflen_words Size of incoming buffer, in number of words
301 errval_t proc_mgmt_client_lmp_bind(struct proc_mgmt_lmp_binding *lmpb,
303 proc_mgmt_bind_continuation_fn *cont,
306 size_t lmp_buflen_words)
308 errval_t err = init_lmp_binding(lmpb, ws, lmp_buflen_words);
309 if (err_is_fail(err)) {
313 lmpb->chan.remote_cap = ep;
315 // Send the local endpoint cap to the process manager.
316 lmpb->chan.connstate = LMP_CONNECTED; /* pre-established */
317 err = lmp_chan_send0(&lmpb->chan, 0, lmpb->chan.local_cap);
318 if (err_is_fail(err)) {
319 // TODO(razvan): This, below.
320 /* XXX: I'm lazily assuming this can never fail with a transient error,
321 * since we only do it once at dispatcher startup. If not, we need to
322 * register and retry here */
323 assert(!lmp_err_is_transient(err));
327 /* Run the RX handler; has a side-effect of registering for receive events */
328 proc_mgmt_lmp_rx_handler(lmpb);
330 /* Run the continuation */
331 cont(st, SYS_ERR_OK, &lmpb->b);
336 errval_t proc_mgmt_bind_client(void)
338 struct proc_mgmt_binding *b = get_proc_mgmt_binding();
345 // Try using nameserver to retrievew the proc mgmt iref.
346 err = nameservice_blocking_lookup("proc_mgmt", &iref);
347 if (err_is_fail(err)) {
352 struct proc_mgmt_bind_retst bindst = {
356 err = proc_mgmt_bind(iref, proc_mgmt_bind_cont, &bindst,
357 get_default_waitset(), /*IDC_BIND_FLAG_RPC_CAP_TRANSFER*/IDC_BIND_FLAGS_DEFAULT);
358 if (err_is_fail(err)) {
359 USER_PANIC_ERR(err, "proc_mgmt_bind");
362 // Wait for bind completion.
363 while (!bindst.present) {
364 messages_wait_and_handle_next();
367 if (err_is_fail(bindst.err)) {
371 proc_mgmt_rpc_client_init(bindst.b);
373 set_proc_mgmt_binding(bindst.b);
378 errval_t proc_mgmt_add_spawnd(iref_t iref, coreid_t core_id)
380 errval_t err = proc_mgmt_bind_client();
381 if (err_is_fail(err)) {
382 DEBUG_ERR(err, "proc_mgmt_bind_client");
386 struct proc_mgmt_binding *b = get_proc_mgmt_binding();
389 err = b->tx_vtbl.add_spawnd(b, NOP_CONT, core_id, iref);
390 if (err_is_fail(err)) {
391 DEBUG_ERR(err, "add_spawnd");
398 * \brief Request the process manager to spawn a program on a specific core
400 * \param coreid Core ID on which to spawn the program
401 * \param path Absolute path in the file system to an executable
402 * image suitable for the given core
403 * \param argv Command-line arguments, NULL-terminated
404 * \param envp Optional environment, NULL-terminated
405 * (pass NULL to inherit)
406 * \param inheritcn_cap Cap to a CNode containing capabilities to be inherited
407 * \param argcn_cap Cap to a CNode containing capabilities passed as
409 * \param flags Flags to spawn
410 * \param ret_domain_cap If non-NULL, filled in with domain cap of new domain
412 * \bug flags are currently ignored
414 errval_t spawn_program_with_caps(coreid_t core_id, const char *path,
417 struct capref inheritcn_cap,
418 struct capref argcn_cap,
420 struct capref *ret_domain_cap)
422 errval_t err, msgerr;
424 // default to copying our environment
429 err = proc_mgmt_bind_client();
430 if (err_is_fail(err)) {
431 USER_PANIC_ERR(err, "proc_mgmt_bind_client");
434 struct proc_mgmt_binding *b = get_proc_mgmt_binding();
437 // construct argument "string"
438 // \0-separated strings in contiguous character buffer
439 // this is needed, as flounder can't send variable-length arrays of strings
440 size_t argstrlen = 0;
442 for (int i = 0; argv[i] != NULL; i++) {
443 argstrlen += strlen(argv[i]) + 1;
446 char argstr[argstrlen];
447 size_t argstrpos = 0;
448 for (int i = 0; argv[i] != NULL; i++) {
449 strcpy(&argstr[argstrpos], argv[i]);
450 argstrpos += strlen(argv[i]);
451 argstr[argstrpos++] = '\0';
453 assert(argstrpos == argstrlen);
455 // repeat for environment
456 size_t envstrlen = 0;
457 for (int i = 0; envp[i] != NULL; i++) {
458 envstrlen += strlen(envp[i]) + 1;
461 char envstr[envstrlen];
462 size_t envstrpos = 0;
463 for (int i = 0; envp[i] != NULL; i++) {
464 strcpy(&envstr[envstrpos], envp[i]);
465 envstrpos += strlen(envp[i]);
466 envstr[envstrpos++] = '\0';
468 assert(envstrpos == envstrlen);
470 // make an unqualified path absolute using the $PATH variable
471 // TODO: implement search (currently assumes PATH is a single directory)
472 char *searchpath = getenv("PATH");
473 if (searchpath == NULL) {
474 searchpath = VFS_PATH_SEP_STR; // XXX: just put it in the root
476 size_t buflen = strlen(path) + strlen(searchpath) + 2;
477 char pathbuf[buflen];
478 if (path[0] != VFS_PATH_SEP) {
479 snprintf(pathbuf, buflen, "%s%c%s", searchpath, VFS_PATH_SEP, path);
480 pathbuf[buflen - 1] = '\0';
481 //vfs_path_normalise(pathbuf);
485 struct capref domain_cap;
486 err = slot_alloc(&domain_cap);
487 if (err_is_fail(err)) {
491 if (capref_is_null(inheritcn_cap) && capref_is_null(argcn_cap)) {
492 err = b->rpc_tx_vtbl.spawn(b, core_id, path, argstr, argstrlen, envstr,
493 envstrlen, flags, &msgerr, &domain_cap);
495 err = b->rpc_tx_vtbl.spawn_with_caps(b, core_id, path, argstr,
496 argstrlen, envstr, envstrlen,
497 inheritcn_cap, argcn_cap, flags,
498 &msgerr, &domain_cap);
500 if (err_is_fail(err)) {
501 USER_PANIC_ERR(err, "error sending spawn request to process manager");
502 } else if (err_is_fail(msgerr)) {
506 if (ret_domain_cap != NULL) {
507 *ret_domain_cap = domain_cap;
516 * \brief Request the process manager to spawn a program on a specific core
518 * \param coreid Core ID on which to spawn the program
519 * \param path Absolute path in the file system to an executable
520 * image suitable for the given core
521 * \param argv Command-line arguments, NULL-terminated
522 * \param envp Optional environment, NULL-terminated
523 * (pass NULL to inherit)
524 * \param inheritcn_cap Cap to a CNode containing capabilities to be inherited
525 * \param argcn_cap Cap to a CNode containing capabilities passed as
527 * \param flags Flags to spawn
528 * \param ret_domain_cap If non-NULL, filled in with domain cap of new domain
530 * \bug flags are currently ignored
532 errval_t spawn_program(coreid_t core_id, const char *path,
533 char *const argv[], char *const envp[],
534 uint8_t flags, struct capref *ret_domain_cap)
536 return spawn_program_with_caps(core_id, path, argv, envp,
537 NULL_CAP, NULL_CAP, flags,
541 errval_t spawn_arrakis_program(coreid_t coreid, const char *path,
542 char *const argv[], char *const envp[],
543 struct capref inheritcn_cap,
544 struct capref argcn_cap, spawn_flags_t flags,
545 domainid_t *ret_domainid)
547 struct arrakis_binding *cl;
548 errval_t err, msgerr;
550 // default to copying our environment
555 // do we have a arrakis client connection for this core?
556 assert(coreid < MAX_CPUS);
557 cl = get_arrakis_binding(coreid);
560 snprintf(namebuf, sizeof(namebuf), "arrakis.%u", coreid);
561 namebuf[sizeof(namebuf) - 1] = '\0';
564 err = nameservice_blocking_lookup(namebuf, &iref);
565 if (err_is_fail(err)) {
566 //DEBUG_ERR(err, "arrakis daemon on core %u not found\n", coreid);
571 struct arrakis_bind_retst bindst = { .present = false };
572 err = arrakis_bind(iref, arrakis_bind_cont, &bindst, get_default_waitset(),
573 IDC_BIND_FLAGS_DEFAULT);
574 if (err_is_fail(err)) {
575 USER_PANIC_ERR(err, "arrakis_bind failed");
578 // XXX: block for bind completion
579 while (!bindst.present) {
580 messages_wait_and_handle_next();
583 if(err_is_fail(bindst.err)) {
584 USER_PANIC_ERR(bindst.err, "asynchronous error during arrakis_bind");
586 assert(bindst.b != NULL);
588 arrakis_rpc_client_init(bindst.b);
589 set_arrakis_binding(coreid, bindst.b);
592 // construct argument "string"
593 // \0-separated strings in contiguous character buffer
594 // this is needed, as flounder can't send variable-length arrays of strings
595 size_t argstrlen = 0;
596 for (int i = 0; argv[i] != NULL; i++) {
597 argstrlen += strlen(argv[i]) + 1;
600 char argstr[argstrlen];
601 size_t argstrpos = 0;
602 for (int i = 0; argv[i] != NULL; i++) {
603 strcpy(&argstr[argstrpos], argv[i]);
604 argstrpos += strlen(argv[i]);
605 argstr[argstrpos++] = '\0';
607 assert(argstrpos == argstrlen);
609 // repeat for environment
610 size_t envstrlen = 0;
611 for (int i = 0; envp[i] != NULL; i++) {
612 envstrlen += strlen(envp[i]) + 1;
615 char envstr[envstrlen];
616 size_t envstrpos = 0;
617 for (int i = 0; envp[i] != NULL; i++) {
618 strcpy(&envstr[envstrpos], envp[i]);
619 envstrpos += strlen(envp[i]);
620 envstr[envstrpos++] = '\0';
622 assert(envstrpos == envstrlen);
625 domainid_t domain_id;
627 // make an unqualified path absolute using the $PATH variable
628 // TODO: implement search (currently assumes PATH is a single directory)
629 char *searchpath = getenv("PATH");
630 if (searchpath == NULL) {
631 searchpath = VFS_PATH_SEP_STR; // XXX: just put it in the root
633 size_t buflen = strlen(path) + strlen(searchpath) + 2;
634 char pathbuf[buflen];
635 if (path[0] != VFS_PATH_SEP) {
636 snprintf(pathbuf, buflen, "%s%c%s", searchpath, VFS_PATH_SEP, path);
637 pathbuf[buflen - 1] = '\0';
638 //vfs_path_normalise(pathbuf);
642 err = cl->rpc_tx_vtbl.spawn_arrakis_domain(cl, path, argstr, argstrlen,
643 envstr, envstrlen, &msgerr, &domain_id);
644 if (err_is_fail(err)) {
645 USER_PANIC_ERR(err, "error sending arrakis request");
646 } else if (err_is_fail(msgerr)) {
650 if (ret_domainid != NULL) {
651 *ret_domainid = domain_id;
658 * \brief Request a program be spawned on all cores in the system
660 * \param same_core Iff false, don't spawn on the same core as the caller
661 * \param path Absolute path in the file system to an executable image
662 * suitable for the given core
663 * \param argv Command-line arguments, NULL-terminated
664 * \param envp Optional environment, NULL-terminated (pass NULL to inherit)
665 * \param flags Flags to spawn
666 * \param ret_domainid If non-NULL, filled in with domain ID of program
667 * \param count How much programs it spawned
669 * \note This function is for legacy compatibility with existing benchmark/test
670 * code, and SHOULD NOT BE USED IN NEW CODE UNLESS YOU HAVE A GOOD REASON!
671 * It doesn't make much sense from a scalability perspective, and is
672 * probably useless on a heterogeneous system.
674 errval_t spawn_program_on_all_cores(bool same_core, const char *path,
675 char *const argv[], char *const envp[],
676 spawn_flags_t flags, struct capref *ret_domain_cap,
677 coreid_t* spawn_count)
679 // TODO: handle flags, domain ID
680 errval_t err = SYS_ERR_OK;
682 struct octopus_binding *r = get_octopus_binding();
684 return LIB_ERR_NAMESERVICE_NOT_BOUND;
687 // FIXME: world's most (kinda less now) broken implementation...
691 static char* spawnds = "r'spawn.[0-9]+' { iref: _ }";
692 struct octopus_get_names_response__rx_args reply;
693 err = r->rpc_tx_vtbl.get_names(r, spawnds, NOP_TRIGGER, reply.output, &reply.tid,
695 if (err_is_fail(err) || err_is_fail(reply.error_code)) {
696 err = err_push(err, SPAWN_ERR_FIND_SPAWNDS);
700 err = oct_parse_names(reply.output, &names, &count);
701 if (err_is_fail(err)) {
705 for (size_t c = 0; c < count; c++) {
707 int ret = sscanf(names[c], "spawn.%hhu", &coreid);
709 err = SPAWN_ERR_MALFORMED_SPAWND_RECORD;
713 if (!same_core && coreid == disp_get_core_id()) {
717 err = spawn_program(c, path, argv, envp, flags, NULL);
718 if (err_is_ok(err) && spawn_count != NULL) {
722 if (err_is_fail(err)) {
723 DEBUG_ERR(err, "error spawning %s on core %u\n", path, c);
729 oct_free_names(names, count);
733 errval_t spawn_binding(coreid_t coreid, struct spawn_binding **ret_client)
735 errval_t err = bind_client(coreid);
736 if (err_is_fail(err)) {
740 *ret_client = get_spawn_binding(coreid);
745 * \brief Request the process manager to span onto a new core.
747 * \param core_id ID of core to span onto.
749 * Blocks until the new dispatcher has established an interdispatcher connection
750 * to the current one.
752 errval_t spawn_span(coreid_t core_id)
754 coreid_t my_core_id = disp_get_core_id();
755 assert (core_id != my_core_id);
757 errval_t err, msgerr;
758 err = proc_mgmt_bind_client();
759 if (err_is_fail(err)) {
760 USER_PANIC_ERR(err, "proc_mgmt_bind_client");
763 struct span_domain_state *st;
764 err = domain_new_dispatcher_setup_only(core_id, &st);
765 if (err_is_fail(err)) {
766 USER_PANIC_ERR(err, "failed to setup new dispatcher");
769 struct proc_mgmt_binding *b = get_proc_mgmt_binding();
772 err = b->rpc_tx_vtbl.span(b, cap_domainid, core_id, st->vroot, st->frame,
774 if (err_is_fail(err)) {
775 USER_PANIC_ERR(err, "error sending span request to process manager");
778 if (err_is_fail(msgerr)) {
782 while(!st->initialized) {
783 event_dispatch(get_default_waitset());
791 * \brief Request the process manager to kill a domain
793 * \param domain_cap Domain ID cap for the victim
795 errval_t spawn_kill(struct capref domain_cap)
797 errval_t err, msgerr;
798 err = proc_mgmt_bind_client();
799 if (err_is_fail(err)) {
800 USER_PANIC_ERR(err, "proc_mgmt_bind_client");
803 struct proc_mgmt_binding *b = get_proc_mgmt_binding();
806 err = b->rpc_tx_vtbl.kill(b, domain_cap, &msgerr);
807 if (err_is_fail(err)) {
808 USER_PANIC_ERR(err, "error sending kill request to process manager");
815 * \brief Inform the process manager about exiting execution.
817 errval_t spawn_exit(uint8_t status)
819 errval_t err = proc_mgmt_bind_client();
820 if (err_is_fail(err)) {
824 struct proc_mgmt_binding *b = get_proc_mgmt_binding();
827 err = b->rpc_tx_vtbl.exit(b, cap_domainid, status);
828 if (err_is_fail(err)) {
836 * \brief Wait for spawned proccess to exit on core.
838 errval_t spawn_wait_coreid(coreid_t coreid, struct capref domain_cap,
839 uint8_t *exitcode, bool nohang)
841 return spawn_wait_core(disp_get_core_id(), domain_cap, exitcode, nohang);
846 * \brief Wait for the termination of a domain on a remote core.
848 errval_t spawn_wait_core(coreid_t coreid, struct capref domain_cap,
849 uint8_t *exitcode, bool nohang)
851 return spawn_wait(domain_cap, exitcode, nohang);
856 * \brief Wait for spawned proccess to exit on current core.
858 errval_t spawn_wait(struct capref domain_cap, uint8_t *status, bool nohang)
860 errval_t err, msgerr;
861 err = proc_mgmt_bind_client();
862 if (err_is_fail(err)) {
866 struct proc_mgmt_binding *b = get_proc_mgmt_binding();
869 err = b->rpc_tx_vtbl.wait(b, domain_cap, &msgerr, status);
870 if (err_is_fail(err)) {
871 USER_PANIC_ERR(err, "error sending wait request to process manager");
877 errval_t spawn_wait_compat(uint8_t domainid,
878 uint8_t *exitcode, bool nohang)
880 errval_t err, reterr;
882 err = bind_client(disp_get_core_id());
883 if (err_is_fail(err)) {
886 struct spawn_binding *cl = get_spawn_binding(disp_get_core_id());
889 err = cl->rpc_tx_vtbl.wait(cl, domainid, nohang, exitcode, &reterr);
890 if (err_is_fail(err)) {
898 * \brief Get the list of domains for ps like implementation
900 errval_t spawn_get_domain_list(uint8_t **domains, size_t *len)
904 struct spawn_binding *cl;
905 err = spawn_binding(disp_get_core_id(), &cl);
906 if (err_is_fail(err)) {
907 USER_PANIC_ERR(err, "spawn_binding");
911 struct spawn_get_domainlist_response__rx_args reply;
912 err = cl->rpc_tx_vtbl.get_domainlist(cl, reply.domains, len);
913 if (err_is_fail(err)) {
914 USER_PANIC_ERR(err, "get_domainlist");
917 *domains = memdup(reply.domains, *len);
922 * \brief Get the status of a domain for ps like implementation
924 errval_t spawn_get_status(uint8_t domain, struct spawn_ps_entry *pse,
925 char **argbuf, size_t *arglen, errval_t *reterr)
929 struct spawn_binding *cl;
930 err = spawn_binding(disp_get_core_id(), &cl);
931 if (err_is_fail(err)) {
932 USER_PANIC_ERR(err, "spawn_binding");
936 struct spawn_status_response__rx_args reply;
937 err = cl->rpc_tx_vtbl.status(cl, domain, (spawn_ps_entry_t *)pse, reply.argv,
939 if (err_is_fail(err)) {
940 USER_PANIC_ERR(err, "status");
943 *argbuf = memdup(reply.argv, *arglen);
948 * \brief Dump capabilities for a given domain
950 errval_t spawn_dump_capabilities_compat(domainid_t domainid)
952 errval_t err, reterr;
954 err = bind_client(disp_get_core_id());
955 if (err_is_fail(err)) {
958 struct spawn_binding *cl = get_spawn_binding(disp_get_core_id());
961 err = cl->rpc_tx_vtbl.dump_capabilities(cl, domainid, &reterr);
962 if (err_is_fail(err)) {
970 * \brief Utility function to create an inherit cnode
971 * and copy caps into it.
973 * \param inheritcn_capp Pointer to capref, filled-in with location of inheritcn
975 * \param fdcap fdcap to copy into inherit cnode.
976 * \param sidcap sidcap to copy into inherit cnode.
977 * \param kernelcap kernelcap to copy into inherit cnode.
979 * \retval SYS_ERR_OK inherticn_capp is allocated and contains copies of the
982 errval_t alloc_inheritcn_with_caps(struct capref *inheritcn_capp,
984 struct capref sidcap,
985 struct capref kernelcap)
989 // construct inherit CNode
990 struct cnoderef inheritcn;
991 err = cnode_create_l2(inheritcn_capp, &inheritcn);
992 if (err_is_fail(err)) {
996 if (!capref_is_null(fdcap)) {
997 // copy fdcap to inherit Cnode
998 struct capref dest = {
1000 .slot = INHERITCN_SLOT_FDSPAGE
1002 err = cap_copy(dest, fdcap);
1003 if (err_is_fail(err)) {
1008 if (!capref_is_null(sidcap)) {
1009 // copy fdcap to inherit Cnode
1010 struct capref dest = {
1012 .slot = INHERITCN_SLOT_SESSIONID
1014 err = cap_copy(dest, sidcap);
1015 if (err_is_fail(err)) {
1020 if (!capref_is_null(kernelcap)) {
1021 // copy fdcap to inherit Cnode
1022 struct capref dest = {
1024 .slot = INHERITCN_SLOT_KERNELCAP
1026 err = cap_copy(dest, kernelcap);
1027 if (err_is_fail(err)) {