Add spawn, spawn_with_caps and span calls to the Process Manager API.
authorRazvan Damachi <razvan.damachi@gmail.com>
Tue, 20 Jun 2017 15:14:58 +0000 (17:14 +0200)
committerSimon Gerber <simon.gerber@inf.ethz.ch>
Thu, 31 Aug 2017 14:35:07 +0000 (16:35 +0200)
The process manager keeps local domain state and forwards valid requests to
spawnds, acting as a proxy for spawning & spanning. Requests are validated as
per the Span-Stop-Cleanup state machine at https://goo.gl/6JuJj2.

Spawnd has been enriched with several asynchronous API calls, in order for
the process manager to serve requests non-blockingly. Specifically, clients of
the process management service issue RPCs to the process manager server
(blockingly), but the latter forwards requests to spawnd asynchronously, hence
it is able to serve multiple clients at the same time.

The client code for spanning uses libbarrelfish/domain.h to create the new
dispatcher for the remote core.

Bug: if the first dispatcher exits main(), dispatchers spanned on other cores
will pagefault.

Signed-off-by: Razvan Damachi <razvan.damachi@gmail.com>

22 files changed:
errors/errno.fugu
if/proc_mgmt.if
if/spawn.if
include/barrelfish/caddr.h
include/barrelfish/domain.h
include/barrelfish/proc_mgmt_client.h
include/barrelfish_kpi/init.h
lib/barrelfish/capabilities.c
lib/barrelfish/domain.c
lib/barrelfish/proc_mgmt_client.c
usr/proc_mgmt/Hakefile
usr/proc_mgmt/domain.c [new file with mode: 0644]
usr/proc_mgmt/domain.h [new file with mode: 0644]
usr/proc_mgmt/pending_clients.c [new file with mode: 0644]
usr/proc_mgmt/pending_clients.h [new file with mode: 0644]
usr/proc_mgmt/service.c
usr/proc_mgmt/spawn_client.c [new file with mode: 0644]
usr/proc_mgmt/spawn_client.h [new file with mode: 0644]
usr/proc_mgmt/spawnd_state.c
usr/proc_mgmt/spawnd_state.h
usr/spawnd/ps.h
usr/spawnd/service.c

index 36485f6..2f59462 100755 (executable)
@@ -654,6 +654,7 @@ errors spawn SPAWN_ERR_ {
     failure COPY_KERNEL_CAP     "Error copying Kernel cap",
     failure COPY_INHERITCN_CAP  "Error copying capability from inherited cnode",
     failure COPY_PROC_MNG_CAP   "Error copying ProcessManager cap",
+    failure COPY_DOMAIN_CAP     "Error copying domain cap",
 
     // make_runnable
     failure DISPATCHER_SETUP    "Dispatcher setup",
@@ -669,8 +670,18 @@ errors spawn SPAWN_ERR_ {
 
 // errors related to the process manager
 errors proc_mgmt PROC_MGMT_ERR_ {
-    failure NOT_MONITOR         "Received monitor-only request from non-monitor domain",
-    failure SPAWND_EXISTS       "Requested spawnd slot already exists",
+    failure NOT_MONITOR          "Received monitor-only request from non-monitor domain",
+    failure SPAWND_EXISTS        "Requested spawnd slot already exists",
+    failure INVALID_SPAWND       "Not connected to spawnd on the requested core",
+    failure CREATE_DOMAIN_CAP    "Failed to create new domain cap",
+    failure SPAWND_REQUEST       "Failed to send request to spawnd",
+    failure DOMAIN_CAP_HASH      "Failed to compute hash code for domain cap",
+    failure CREATE_CLIENTS_TABLE "Failed to create pending clients hash table",
+    failure CLIENTS_TABLE_FIND   "Failed to find requested client in pending clients table",
+    failure CREATE_DOMAIN_TABLE  "Failed to create domain hash table",
+    failure DOMAIN_TABLE_FIND    "Failed to find requested domain in domain table",
+    failure DOMAIN_NOT_RUNNING   "Domain is not currently running",
+    failure ALREADY_SPANNED      "Domain has already been spanned to the given core",
 };
 
 // errors from ELF library
index 07a73d3..3309307 100644 (file)
@@ -12,25 +12,39 @@ interface proc_mgmt "Process management service" {
   // Add a new spawnd to the process manager's list.
   message add_spawnd(coreid core, iref iref);
 
-  // Spawn a new domain, returning its domainid cap.
-  /*
+  // Spawn a new domain, returning its domain cap.
   rpc spawn(in coreid core,
             in String path[2048],
             in char argvbuf[argvbytes, 2048],
             in char envbuf[envbytes, 2048],
             in uint8 flags,
             out errval err,
-            out cap domainid_cap);
+            out cap domain_cap);
+
+  rpc spawn_with_caps(in coreid core,
+                      in String path[2048],
+                      in char argvbuf[argvbytes, 2048],
+                      in char envbuf[envbytes, 2048],
+                      in cap inheritcn_cap,
+                      in cap argcn_cap,
+                      in uint8 flags,
+                      out errval err,
+                      out cap domain_cap);
+
+  // Span a new core for a given domain, based on provided vroot and dispframe.
+  rpc span(in cap domain_cap, in coreid core, in cap vroot, in cap dispframe,
+           out errval err);
 
+  // Kill a domain for which the caller has a domain cap.
+  rpc kill(in cap domain_cap, out errval err);
+
+  /*
   // Span the caller to a new core.
   rpc span(in cap domainid_cap,
            in coreid core,
            in cap vroot,
            in cap disp_mem,
            out errval err);
-
-  // Kill a domain for which the caller has a domainid cap.
-  rpc kill(in cap domainid_cap, out errval err);
   */
 
   // TODO(razvan): exit, wait, status, some other calls from spawn.if?
index 59bba6c..cf1ea52 100644 (file)
@@ -20,6 +20,41 @@ interface spawn "Interface to spawn domains" {
                                in cap argcn_cap, in uint8 flags, out errval err,
                                out domainid domain_id);
 
+    // Messages for the async interface with the process manager.
+    message spawn_request(cap domain_cap,
+                          String path[2048],
+                          char argvbuf[argvbytes, 2048],
+                          char envbuf[envbytes, 2048],
+                          uint8 flags);
+    message spawn_with_caps_request(cap domain_cap,
+                                    String path[2048],
+                                    char argvbuf[argvbytes, 2048],
+                                    char envbuf[envbytes, 2048],
+                                    cap inheritcn_cap,
+                                    cap argcn_cap,
+                                    uint8 flags);
+    message span_request(cap domain_cap, cap vroot, cap dispframe);
+    message kill_request(cap domain_cap);
+    message spawn_reply(cap domain_cap, errval err);
+
+    rpc spawn_proc_mgmt_domain(in cap domain_cap,
+                               in String path[2048],
+                               in char argvbuf[argvbytes, 2048],
+                               in char envbuf[envbytes, 2048],
+                               in uint8 flags,
+                               out errval err);
+
+    rpc spawn_proc_mgmt_domain_with_caps(in cap domain_cap,
+                                         in String path[2048],
+                                         in char argvbuf[argvbytes, 2048],
+                                         in char envbuf[envbytes, 2048],
+                                         in cap inheritcn_cap,
+                                         in cap argcn_cap,
+                                         in uint8 flags,
+                                         out errval err);
+
+    rpc span(in cap domain_cap, in cap vroot, in cap dispframe, out errval err);
+
     rpc use_local_memserv();
     rpc kill(in domainid domain_id, out errval err);
 
@@ -39,6 +74,4 @@ interface spawn "Interface to spawn domains" {
 
     // Capability debugging
     rpc dump_capabilities(in domainid domain_id, out errval err);
-
-    rpc echo(in String sender_name[2048], in coreid sender_core);
 };
index 4874a52..2f1ca01 100644 (file)
@@ -104,7 +104,8 @@ extern struct cnoderef cnode_root, cnode_task, cnode_base, cnode_super,
 /* well-known capabilities */
 extern struct capref cap_root, cap_monitorep, cap_irq, cap_io, cap_dispatcher,
                      cap_selfep, cap_kernel, cap_initep, cap_perfmon, cap_dispframe,
-                     cap_sessionid, cap_ipi, cap_vroot, cap_argcn, cap_procmng;
+                     cap_sessionid, cap_ipi, cap_vroot, cap_argcn, cap_procmng,
+                     cap_domainid;
 
 /**
  * \brief Returns the depth in the CSpace address of a cap
index 5c3c119..0ef645a 100644 (file)
 #define BARRELFISH_DOMAIN_H
 
 #include <sys/cdefs.h>
+#include <barrelfish/event_queue.h>
 #include <barrelfish/threads.h>
 
 __BEGIN_DECLS
 
 typedef void (*domain_spanned_callback_t)(void *arg, errval_t err);
 
+///< Struct for spanning domains state machine
+struct span_domain_state {
+    struct thread *thread;              ///< Thread to run on remote core
+    uint8_t core_id;                    ///< Id of the remote core
+    errval_t err;                       ///< To propagate error value
+    domain_spanned_callback_t callback; ///< Callback for when domain has spanned
+    void *callback_arg;                 ///< Optional argument to pass with callback
+    struct capref frame;                ///< Dispatcher frame
+    struct capref vroot;                ///< VRoot cap
+    struct event_queue_node event_qnode;       ///< Event queue node
+    struct waitset_chanstate initev;    ///< Dispatcher initialized event
+    bool initialized;                   ///< True if remote initialized
+};
+
 struct mem_binding;
 struct octopus_binding;
 struct monitor_binding;
@@ -73,6 +88,8 @@ errval_t domain_init(void);
 errval_t domain_new_dispatcher(coreid_t core_id,
                                domain_spanned_callback_t callback,
                                void *callback_arg);
+errval_t domain_new_dispatcher_setup_only(coreid_t core_id,
+                                          struct span_domain_state **ret_state);
 errval_t domain_thread_create_on(coreid_t core_id, thread_func_t start_func,
                                  void *arg, struct thread **newthread);
 errval_t domain_thread_create_on_varstack(coreid_t core_id,
index a5d54da..ad489c2 100644 (file)
@@ -34,6 +34,16 @@ errval_t proc_mgmt_client_lmp_bind(struct proc_mgmt_lmp_binding *lmpb,
 errval_t proc_mgmt_bind_client(void);
 
 errval_t proc_mgmt_add_spawnd(iref_t iref, coreid_t core_id);
+errval_t proc_mgmt_spawn_program(coreid_t core_id, const char *path,
+                                    char *const argv[], char *const envp[],
+                                 uint8_t flags, struct capref *ret_domain_cap);
+errval_t proc_mgmt_spawn_program_with_caps(coreid_t core_id, const char *path,
+                                 char *const argv[], char *const envp[],
+                                 struct capref inheritcn_cap,
+                                 struct capref argcn_cap, uint8_t flags,
+                                 struct capref *ret_domain_cap);
+errval_t proc_mgmt_span(coreid_t core_id);
+errval_t proc_mgmt_kill(struct capref domain_cap);
 
 __END_DECLS
 
index 9ee3173..4669317 100644 (file)
@@ -96,7 +96,8 @@
 #define TASKCN_SLOT_COREBOOT    16  ///< Copy of realmode section used to bootstrap a core
 #define TASKCN_SLOT_IPI         17  ///< Copy of IPI cap
 #define TASKCN_SLOT_PROC_MNG    18  ///< Cap for the process manager
-#define TASKCN_SLOTS_USER       19  ///< First free slot in taskcn for user
+#define TASKCN_SLOT_DOMAINID    19  ///< Domain ID cap
+#define TASKCN_SLOTS_USER       20  ///< First free slot in taskcn for user
 
 /* Page CNode */
 #define PAGECN_SLOT_VROOT       0 ///< First slot of page cnode is root page table
index c167b77..f0c313e 100644 (file)
@@ -153,6 +153,12 @@ struct capref cap_procmng = {
     .slot = TASKCN_SLOT_PROC_MNG
 };
 
+/// Domain ID cap.
+struct capref cap_domainid = {
+    .cnode = TASK_CNODE_INIT,
+    .slot = TASKCN_SLOT_DOMAINID
+};
+
 /// Root PML4 VNode
 struct capref cap_vroot = {
     .cnode = PAGE_CNODE_INIT,
index 93400a5..f528ae5 100644 (file)
@@ -55,20 +55,6 @@ struct remote_core_state {
     size_t pagesize;              ///< the pagesize to be used for the heap
 };
 
-///< Struct for spanning domains state machine
-struct span_domain_state {
-    struct thread *thread;              ///< Thread to run on remote core
-    uint8_t core_id;                    ///< Id of the remote core
-    errval_t err;                       ///< To propagate error value
-    domain_spanned_callback_t callback; ///< Callback for when domain has spanned
-    void *callback_arg;                 ///< Optional argument to pass with callback
-    struct capref frame;                ///< Dispatcher frame
-    struct capref vroot;                ///< VRoot cap
-    struct event_queue_node event_qnode;       ///< Event queue node
-    struct waitset_chanstate initev;    ///< Dispatcher initialized event
-    bool initialized;                   ///< True if remote initialized
-};
-
 ///< Array of all interdisp IREFs in the domain
 static iref_t allirefs[MAX_CPUS];
 
@@ -444,6 +430,7 @@ static int interdisp_msg_handler(void *arg)
     struct waitset *ws = arg;
     assert(ws != NULL);
 
+    debug_printf("Looping on inter-dispatcher message handler\n");
     for(;;) {
         errval_t err = event_dispatch(ws);
         if(err_is_fail(err)) {
@@ -506,8 +493,6 @@ static int remote_core_init_enabled(void *arg)
     st->default_waitset_handler = thread_create(span_slave_thread, NULL);
     assert(st->default_waitset_handler != NULL);
 
-
-
     return interdisp_msg_handler(&st->interdisp_ws);
 }
 
@@ -589,7 +574,6 @@ static void span_domain_reply(struct monitor_binding *mb,
     } else { /* Use debug_err if no callback registered */
         DEBUG_ERR(msgerr, "Failure in span_domain_reply");
     }
-    free(span_domain_state);
 }
 
 static void span_domain_request_sender(void *arg)
@@ -631,18 +615,15 @@ static void span_domain_request_sender_wrapper(void *st)
  */
 static errval_t domain_new_dispatcher_varstack(coreid_t core_id,
                                                domain_spanned_callback_t callback,
-                                               void *callback_arg, size_t stack_size)
+                                               void *callback_arg, size_t stack_size,
+                                               struct span_domain_state **ret_span_state)
 {
     assert(core_id != disp_get_core_id());
 
     errval_t err;
     struct domain_state *domain_state = get_domain_state();
-    struct monitor_binding *mb = get_monitor_binding();
     assert(domain_state != NULL);
 
-    /* Set reply handler */
-    mb->rx_vtbl.span_domain_reply = span_domain_reply;
-
     while(domain_state->iref == 0) { /* If not initialized, wait */
         messages_wait_and_handle_next();
     }
@@ -773,8 +754,40 @@ static errval_t domain_new_dispatcher_varstack(coreid_t core_id,
         assert(domain_state->default_waitset_handler != NULL);
     }
 #endif
+
+    if (ret_span_state != NULL) {
+        *ret_span_state = span_domain_state;
+    }
+
+    return SYS_ERR_OK;
+}
+
+/**
+ * \brief Creates a dispatcher on a remote core
+ *
+ * \param core_id   Id of the core to create the dispatcher on
+ * \param callback  Callback to use when new dispatcher is created
+ *
+ * The new dispatcher is created with the same vroot, sharing the same vspace.
+ * The new dispatcher also has a urpc connection to the core that created it.
+ */
+errval_t domain_new_dispatcher(coreid_t core_id,
+                               domain_spanned_callback_t callback,
+                               void *callback_arg)
+{
+    struct span_domain_state *span_domain_state;
+    errval_t err = domain_new_dispatcher_varstack(core_id,
+                                                  callback, callback_arg,
+                                                  THREADS_DEFAULT_STACK_BYTES,
+                                                  &span_domain_state);
+    if (err_is_fail(err)) {
+        return err;
+    }
+
     /* Wait to use the monitor binding */
     struct monitor_binding *mcb = get_monitor_binding();
+    /* Set reply handler */
+    mcb->rx_vtbl.span_domain_reply = span_domain_reply;
     event_mutex_enqueue_lock(&mcb->mutex, &span_domain_state->event_qnode,
                           (struct event_closure) {
                               .handler = span_domain_request_sender_wrapper,
@@ -784,27 +797,29 @@ static errval_t domain_new_dispatcher_varstack(coreid_t core_id,
         event_dispatch(get_default_waitset());
     }
 
-    /* Free state */
     free(span_domain_state);
 
     return SYS_ERR_OK;
 }
 
 /**
- * \brief Creates a dispatcher on a remote core
+ * \brief Creates a dispatcher for a remote core, without running it.
  *
  * \param core_id   Id of the core to create the dispatcher on
- * \param callback  Callback to use when new dispatcher is created
+ * \param ret_state If non-null, will contain the spanned domain state, which
+ *                  can be used to retrieve the vroot and dispframe, as well as
+ *                  to check when the new dispatcher is up
  *
  * The new dispatcher is created with the same vroot, sharing the same vspace.
  * The new dispatcher also has a urpc connection to the core that created it.
  */
-errval_t domain_new_dispatcher(coreid_t core_id,
-                               domain_spanned_callback_t callback,
-                               void *callback_arg)
+errval_t domain_new_dispatcher_setup_only(coreid_t core_id,
+                                          struct span_domain_state **ret_state)
 {
-    return domain_new_dispatcher_varstack(core_id, callback, callback_arg,
-                                          THREADS_DEFAULT_STACK_BYTES);
+    assert(ret_state != NULL);
+    return domain_new_dispatcher_varstack(core_id, NULL, NULL,
+                                          THREADS_DEFAULT_STACK_BYTES,
+                                          ret_state);
 }
 
 errval_t domain_send_cap(coreid_t core_id, struct capref cap)
index c12be3b..130c868 100644 (file)
@@ -17,6 +17,7 @@
 #include <barrelfish/proc_mgmt_client.h>
 #include <if/octopus_defs.h>
 #include <if/proc_mgmt_defs.h>
+#include <vfs/vfs_path.h>
 
 struct proc_mgmt_bind_retst {
     errval_t err;
@@ -24,6 +25,8 @@ struct proc_mgmt_bind_retst {
     bool present;
 };
 
+extern char **environ;
+
 static void error_handler(struct proc_mgmt_binding *b, errval_t err)
 {
 #if defined(__x86_64__) || defined(__i386__)
@@ -275,3 +278,212 @@ errval_t proc_mgmt_add_spawnd(iref_t iref, coreid_t core_id)
 
     return err;
 }
+
+/**
+ * \brief Request the process manager to spawn a program on a specific core
+ *
+ * \param coreid          Core ID on which to spawn the program
+ * \param path            Absolute path in the file system to an executable
+ *                        image suitable for the given core
+ * \param argv            Command-line arguments, NULL-terminated
+ * \param envp            Optional environment, NULL-terminated
+ *                        (pass NULL to inherit)
+ * \param inheritcn_cap   Cap to a CNode containing capabilities to be inherited
+ * \param argcn_cap       Cap to a CNode containing capabilities passed as
+ *                        arguments
+ * \param flags           Flags to spawn
+ * \param ret_domain_cap  If non-NULL, filled in with domain cap of new domain
+ *
+ * \bug flags are currently ignored
+ */
+errval_t proc_mgmt_spawn_program_with_caps(coreid_t core_id, const char *path,
+                                           char *const argv[],
+                                           char *const envp[],
+                                           struct capref inheritcn_cap,
+                                           struct capref argcn_cap,
+                                           uint8_t flags,
+                                           struct capref *ret_domain_cap)
+{
+    errval_t err, msgerr;
+
+    // default to copying our environment
+    if (envp == NULL) {
+        envp = environ;
+    }
+
+    err = proc_mgmt_bind_client();
+    if (err_is_fail(err)) {
+        USER_PANIC_ERR(err, "proc_mgmt_bind_client");
+    }
+
+    struct proc_mgmt_binding *b = get_proc_mgmt_binding();
+    assert(b != NULL);
+
+    // construct argument "string"
+    // \0-separated strings in contiguous character buffer
+    // this is needed, as flounder can't send variable-length arrays of strings
+    size_t argstrlen = 0;
+    for (int i = 0; argv[i] != NULL; i++) {
+        argstrlen += strlen(argv[i]) + 1;
+    }
+
+    char argstr[argstrlen];
+    size_t argstrpos = 0;
+    for (int i = 0; argv[i] != NULL; i++) {
+        strcpy(&argstr[argstrpos], argv[i]);
+        argstrpos += strlen(argv[i]);
+        argstr[argstrpos++] = '\0';
+    }
+    assert(argstrpos == argstrlen);
+
+    // repeat for environment
+    size_t envstrlen = 0;
+    for (int i = 0; envp[i] != NULL; i++) {
+        envstrlen += strlen(envp[i]) + 1;
+    }
+
+    char envstr[envstrlen];
+    size_t envstrpos = 0;
+    for (int i = 0; envp[i] != NULL; i++) {
+        strcpy(&envstr[envstrpos], envp[i]);
+        envstrpos += strlen(envp[i]);
+        envstr[envstrpos++] = '\0';
+    }
+    assert(envstrpos == envstrlen);
+
+    // make an unqualified path absolute using the $PATH variable
+    // TODO: implement search (currently assumes PATH is a single directory)
+    char *searchpath = getenv("PATH");
+    if (searchpath == NULL) {
+        searchpath = VFS_PATH_SEP_STR; // XXX: just put it in the root
+    }
+    size_t buflen = strlen(path) + strlen(searchpath) + 2;
+    char pathbuf[buflen];
+    if (path[0] != VFS_PATH_SEP) {
+        snprintf(pathbuf, buflen, "%s%c%s", searchpath, VFS_PATH_SEP, path);
+        pathbuf[buflen - 1] = '\0';
+        //vfs_path_normalise(pathbuf);
+        path = pathbuf;
+    }
+
+    struct capref domain_cap;
+
+    if (capref_is_null(inheritcn_cap) && capref_is_null(argcn_cap)) {
+        err = b->rpc_tx_vtbl.spawn(b, core_id, path, argstr, argstrlen, envstr,
+                                   envstrlen, flags, &msgerr, &domain_cap);
+    } else {
+        err = b->rpc_tx_vtbl.spawn_with_caps(b, core_id, path, argstr,
+                                             argstrlen, envstr, envstrlen,
+                                             inheritcn_cap, argcn_cap, flags,
+                                             &msgerr, &domain_cap);
+    }
+    if (err_is_fail(err)) {
+        USER_PANIC_ERR(err, "error sending spawn request to process manager");
+    } else if (err_is_fail(msgerr)) {
+        goto out;
+    }
+
+    if (ret_domain_cap != NULL) {
+        *ret_domain_cap = domain_cap;
+    }
+
+out:
+    return msgerr;
+    
+}
+
+/**
+ * \brief Request the process manager to spawn a program on a specific core
+ *
+ * \param coreid          Core ID on which to spawn the program
+ * \param path            Absolute path in the file system to an executable
+ *                        image suitable for the given core
+ * \param argv            Command-line arguments, NULL-terminated
+ * \param envp            Optional environment, NULL-terminated
+ *                        (pass NULL to inherit)
+ * \param inheritcn_cap   Cap to a CNode containing capabilities to be inherited
+ * \param argcn_cap       Cap to a CNode containing capabilities passed as
+ *                        arguments
+ * \param flags           Flags to spawn
+ * \param ret_domain_cap  If non-NULL, filled in with domain cap of new domain
+ *
+ * \bug flags are currently ignored
+ */
+errval_t proc_mgmt_spawn_program(coreid_t core_id, const char *path,
+                                 char *const argv[], char *const envp[],
+                                 uint8_t flags, struct capref *ret_domain_cap)
+{
+    return proc_mgmt_spawn_program_with_caps(core_id, path, argv, envp,
+                                             NULL_CAP, NULL_CAP, flags,
+                                             ret_domain_cap);
+}
+
+/**
+ * \brief Request the process manager to span onto a new core.
+ *
+ * \param core_id ID of core to span onto.
+ *
+ * Blocks until the new dispatcher has established an interdispatcher connection
+ * to the current one.
+ */
+errval_t proc_mgmt_span(coreid_t core_id)
+{
+    coreid_t my_core_id = disp_get_core_id();
+    assert (core_id != my_core_id);
+
+    errval_t err, msgerr;
+    err = proc_mgmt_bind_client();
+    if (err_is_fail(err)) {
+        USER_PANIC_ERR(err, "proc_mgmt_bind_client");
+    }
+    
+    struct span_domain_state *st;
+    err = domain_new_dispatcher_setup_only(core_id, &st);
+    if (err_is_fail(err)) {
+        USER_PANIC_ERR(err, "failed to setup new dispatcher");
+    }
+
+    struct proc_mgmt_binding *b = get_proc_mgmt_binding();
+    assert(b != NULL);
+
+    err = b->rpc_tx_vtbl.span(b, cap_domainid, core_id, st->vroot, st->frame,
+                              &msgerr);
+    if (err_is_fail(err)) {
+        USER_PANIC_ERR(err, "error sending span request to process manager");
+    }
+
+    if (err_is_fail(msgerr)) {
+        return msgerr;
+    }
+
+    while(!st->initialized) {
+        event_dispatch(get_default_waitset());
+    }
+    free(st);
+
+    return SYS_ERR_OK;
+}
+
+/**
+ * \brief Request the process manager to kill a domain
+ *
+ * \param domain_cap Domain ID cap for the victim
+ */
+errval_t proc_mgmt_kill(struct capref domain_cap)
+{
+    errval_t err, msgerr;
+    err = proc_mgmt_bind_client();
+    if (err_is_fail(err)) {
+        USER_PANIC_ERR(err, "proc_mgmt_bind_client");
+    }
+
+    struct proc_mgmt_binding *b = get_proc_mgmt_binding();
+    assert(b != NULL);
+
+    err = b->rpc_tx_vtbl.kill(b, domain_cap, &msgerr);
+    if (err_is_fail(err)) {
+        USER_PANIC_ERR(err, "error sending kill request to process manager");
+    }
+
+    return msgerr;
+}
index 7b02d9a..6da0259 100644 (file)
 --------------------------------------------------------------------------
 
 [ build application { target = "proc_mgmt",
-                      cFiles = [ "main.c", "service.c", "spawnd_state.c" ],
-                      addLibraries = libDeps [ "skb", "dist", "lwip" ],
+                      cFiles = [ "main.c", "service.c", "spawnd_state.c", 
+                                 "domain.c", "pending_clients.c" ],
+                      addLibraries = libDeps [ "skb", "dist", "lwip",
+                                               "collections" ],
                       flounderDefs = [ "monitor", "monitor_blocking" ],
                       flounderExtraDefs = [ ("monitor_blocking",["rpcclient"]), 
                                             ("spawn",["rpcclient"]) ],
                       architectures = [ "x86_64", "x86_32" ]
                     },
   build application { target = "proc_mgmt",
-                      cFiles = [ "main.c", "service.c", "spawnd_state.c" ],
-                      addLibraries = libDeps [ "skb", "dist", "lwip" ],
+                      cFiles = [ "main.c", "service.c", "spawnd_state.c", 
+                                 "domain.c", "pending_clients.c" ],
+                      addLibraries = libDeps [ "skb", "dist", "lwip",
+                                               "collections" ],
                       flounderDefs = [ "monitor", "monitor_blocking"],
                       flounderExtraDefs = [ ("monitor_blocking",["rpcclient"]), 
                                             ("spawn",["rpcclient"]) ],
                       architectures = [ "k1om" ]
                     },
   build application { target = "proc_mgmt",
-                      cFiles = [ "main.c", "service.c", "spawnd_state.c" ],
-                      addLibraries = libDeps [ "skb", "dist", "lwip" ],
+                      cFiles = [ "main.c", "service.c", "spawnd_state.c", 
+                                 "domain.c", "pending_clients.c" ],
+                      addLibraries = libDeps [ "skb", "dist", "lwip",
+                                               "collections" ],
                       flounderDefs = [ "monitor", "monitor_blocking"],
                       flounderExtraDefs = [ ("monitor_blocking",["rpcclient"]), 
                                             ("spawn",["rpcclient"]) ],
diff --git a/usr/proc_mgmt/domain.c b/usr/proc_mgmt/domain.c
new file mode 100644 (file)
index 0000000..1c09dad
--- /dev/null
@@ -0,0 +1,176 @@
+/*
+ * \brief Domain internals for the process manager.
+ *
+ * Copyright (c) 2017, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#include <barrelfish/barrelfish.h>
+#include <collections/hash_table.h>
+
+#include "domain.h"
+
+#define HASH_INDEX_BUCKETS 6151
+static collections_hash_table* domain_table = NULL;
+
+errval_t domain_cap_hash(struct capref domain_cap, uint64_t *ret_hash)
+{
+    assert(ret_hash != NULL);
+
+    struct capability ret_cap;
+    errval_t err = debug_cap_identify(domain_cap, &ret_cap);
+    if (err_is_fail(err)) {
+        return err_push(err, PROC_MGMT_ERR_DOMAIN_CAP_HASH);
+    }
+    assert(ret_cap.type == ObjType_Domain);
+
+    static uint64_t base = 1 + (uint64_t) MAX_COREID;
+    *ret_hash = base * ret_cap.u.domain.coreid + ret_cap.u.domain.core_local_id;
+
+    return SYS_ERR_OK;
+}
+
+errval_t domain_new(struct capref domain_cap, struct domain_entry **ret_entry)
+{
+    assert(ret_entry != NULL);
+
+    struct domain_entry *entry = (struct domain_entry*) malloc(
+            sizeof(struct domain_entry));
+    if (entry == NULL) {
+        return LIB_ERR_MALLOC_FAIL;
+    }
+
+    entry->domain_cap = domain_cap;
+    entry->status = DOMAIN_STATUS_NIL;
+    entry->spawnds = NULL;
+    entry->waiters = NULL;
+
+    if (domain_table == NULL) {
+        collections_hash_create_with_buckets(&domain_table, HASH_INDEX_BUCKETS,
+                                             NULL);
+        if (domain_table == NULL) {
+            return PROC_MGMT_ERR_CREATE_DOMAIN_TABLE;
+        }
+    }
+
+    uint64_t key;
+    errval_t err = domain_cap_hash(entry->domain_cap, &key);
+    if (err_is_fail(err)) {
+        return err;
+    }
+
+    collections_hash_insert(domain_table, key, entry);
+
+    *ret_entry = entry;
+
+    return SYS_ERR_OK;
+}
+
+errval_t domain_get_by_cap(struct capref domain_cap,
+                           struct domain_entry **ret_entry)
+{
+    assert(ret_entry != NULL);
+
+    uint64_t key;
+    errval_t err = domain_cap_hash(domain_cap, &key);
+    if (err_is_fail(err)) {
+        return err;
+    }
+
+    void *table_entry = collections_hash_find(domain_table, key);
+    if (table_entry == NULL) {
+        return PROC_MGMT_ERR_DOMAIN_TABLE_FIND;
+    }
+    *ret_entry = (struct domain_entry*) table_entry;
+
+    return SYS_ERR_OK;
+}
+
+void domain_run_on_spawnd(struct domain_entry *entry,
+                          struct spawnd_state *spawnd)
+{
+    assert(entry != NULL);
+    assert(spawnd != NULL);
+    assert(entry->status == DOMAIN_STATUS_NIL ||
+           entry->status == DOMAIN_STATUS_RUNNING);
+
+    entry->status = DOMAIN_STATUS_RUNNING;
+
+    struct domain_spawnd_state *st = (struct domain_spawnd_state*) malloc(
+            sizeof(struct domain_spawnd_state));
+    st->spawnd_state = spawnd;
+    st->next = entry->spawnds;
+    entry->spawnds = st;
+}
+
+errval_t domain_spawn(struct capref domain_cap, coreid_t core_id)
+{
+    struct domain_entry *entry = NULL;
+    errval_t err = domain_new(domain_cap, &entry);
+    if (err_is_fail(err)) {
+        if (entry != NULL) {
+            free(entry);
+        }
+        return err;
+    }
+
+    domain_run_on_spawnd(entry, spawnd_state_get(core_id));
+
+    return SYS_ERR_OK;
+}
+
+errval_t domain_can_span(struct capref domain_cap, coreid_t core_id)
+{
+    struct domain_entry *entry = NULL;
+    errval_t err = domain_get_by_cap(domain_cap, &entry);
+    if (err_is_fail(err)) {
+        return err;
+    }
+
+    assert(entry != NULL);
+    if (entry->status != DOMAIN_STATUS_RUNNING) {
+        return PROC_MGMT_ERR_DOMAIN_NOT_RUNNING;
+    }
+
+    struct domain_spawnd_state *st = entry->spawnds;
+    while (st != NULL) {
+        if (st->spawnd_state->core_id == core_id) {
+            // TODO(razvan): Maybe we want to allow the same domain to span
+            // multiple dispatcher onto the same core?
+            return PROC_MGMT_ERR_ALREADY_SPANNED;
+        }
+        st = st->next;
+    }
+
+    return SYS_ERR_OK;
+}
+
+errval_t domain_span(struct capref domain_cap, coreid_t core_id)
+{
+    struct domain_entry *entry = NULL;
+    errval_t err = domain_get_by_cap(domain_cap, &entry);
+    if (err_is_fail(err)) {
+        return err;
+    }
+    assert(entry != NULL);
+
+    domain_run_on_spawnd(entry, spawnd_state_get(core_id));
+
+    return SYS_ERR_OK;
+}
+
+void domain_send_stop(struct domain_entry *entry)
+{
+    assert(entry != NULL);
+
+    struct domain_spawnd_state *st = entry->spawnds;
+    while (st != NULL) {
+        debug_printf("Simulating STOP message to spawnd at binding %p\n",
+                     st->spawnd_state->b);
+        st = st->next;
+    }
+}
diff --git a/usr/proc_mgmt/domain.h b/usr/proc_mgmt/domain.h
new file mode 100644 (file)
index 0000000..cf37c72
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * \brief Domain internals for the process manager.
+ *
+ * Copyright (c) 2017, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#ifndef PROC_MGMT_DOMAIN_H
+#define PROC_MGMT_DOMAIN_H
+
+#include <barrelfish/barrelfish.h>
+#include <if/proc_mgmt_defs.h>
+
+#include "spawnd_state.h"
+
+enum domain_status {
+    DOMAIN_STATUS_NIL,
+    DOMAIN_STATUS_RUNNING,
+    DOMAIN_STATUS_STOP_PEND,
+    DOMAIN_STATUS_STOPPED
+    // TODO(razvan): Add the others, as per the state machine.
+};
+
+struct domain_waiter {
+    struct proc_mgmt_binding *b;
+    struct domain_waiter *next;
+};
+
+struct domain_spawnd_state {
+    struct spawnd_state *spawnd_state;
+    struct domain_spawnd_state *next;
+};
+
+struct domain_entry {
+    struct capref domain_cap;              // Unique domain ID cap.
+    enum domain_status status;             // Current domain state.
+    struct domain_spawnd_state *spawnds;   // Spawnds running this domain.
+    struct domain_waiter *waiters;         // Clients waiting after this domain.
+};
+
+errval_t domain_cap_hash(struct capref domain_cap, uint64_t *ret_hash);
+errval_t domain_new(struct capref domain_cap, struct domain_entry **ret_entry);
+errval_t domain_get_by_cap(struct capref domain_cap,
+                           struct domain_entry **ret_entry);
+void domain_run_on_spawnd(struct domain_entry *entry,
+                          struct spawnd_state *spawnd);
+
+errval_t domain_spawn(struct capref domain_cap, coreid_t core_id);
+errval_t domain_can_span(struct capref domain_cap, coreid_t core_id);
+errval_t domain_span(struct capref domain_cap, coreid_t core_id);
+void domain_send_stop(struct domain_entry *entry);
+// TODO(razvan): domain_exists, domain_remove etc.
+
+#endif  // PROC_MGMT_DOMAIN_H
\ No newline at end of file
diff --git a/usr/proc_mgmt/pending_clients.c b/usr/proc_mgmt/pending_clients.c
new file mode 100644 (file)
index 0000000..d4ff3ae
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * \brief Client handling internals for the process manager.
+ *
+ * Copyright (c) 2017, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#include <collections/hash_table.h>
+
+#include "domain.h"
+#include "pending_clients.h"
+
+static collections_hash_table* pending_clients_table = NULL;
+
+errval_t pending_clients_add(struct capref domain_cap,
+                             struct proc_mgmt_binding *b, enum ClientType type,
+                             coreid_t core_id)
+{
+    if (pending_clients_table == NULL) {
+        collections_hash_create_with_buckets(&pending_clients_table,
+                                             HASH_INDEX_BUCKETS, NULL);
+        if (pending_clients_table == NULL) {
+            return PROC_MGMT_ERR_CREATE_CLIENTS_TABLE;
+        }
+    }
+
+    uint64_t key;
+    errval_t err = domain_cap_hash(domain_cap, &key);
+    if (err_is_fail(err)) {
+        return err;
+    }
+
+    struct pending_client *client = (struct pending_client*) malloc(
+            sizeof(struct pending_client));
+    client->b = b;
+    client->core_id = core_id;
+    client->type = type;
+    collections_hash_insert(pending_clients_table, key, client);
+
+    return SYS_ERR_OK;
+}
+
+errval_t pending_clients_release(struct capref domain_cap,
+                                        struct pending_client *ret_cl)
+{
+    uint64_t key;
+    errval_t err = domain_cap_hash(domain_cap, &key);
+    if (err_is_fail(err)) {
+        return err;
+    }
+
+    void *table_entry = collections_hash_find(pending_clients_table, key);
+    if (table_entry == NULL) {
+        return PROC_MGMT_ERR_CLIENTS_TABLE_FIND;
+    }
+    if (ret_cl != NULL) {
+        *ret_cl = *((struct pending_client*) table_entry);
+    }
+
+    collections_hash_delete(pending_clients_table, key);
+
+    return SYS_ERR_OK;
+}
diff --git a/usr/proc_mgmt/pending_clients.h b/usr/proc_mgmt/pending_clients.h
new file mode 100644 (file)
index 0000000..f5c2a4f
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * \brief Client handling internals for the process manager.
+ *
+ * Copyright (c) 2017, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#ifndef PENDING_CLIENTS_H
+#define PENDING_CLIENTS_H
+
+#include <barrelfish/barrelfish.h>
+#include <if/proc_mgmt_defs.h>
+
+#define HASH_INDEX_BUCKETS 6151
+
+enum ClientType {
+       ClientType_Spawn,
+       ClientType_SpawnWithCaps,
+       ClientType_Span,
+       ClientType_Kill,
+       ClientType_Wait
+       // TODO(razvan): Others?
+};
+
+struct pending_client {
+    struct proc_mgmt_binding *b;
+    coreid_t core_id;
+    enum ClientType type;
+};
+
+errval_t pending_clients_add(struct capref domain_cap,
+                             struct proc_mgmt_binding *b, enum ClientType type,
+                             coreid_t core_id);
+errval_t pending_clients_release(struct capref domain_cap,
+                                 struct pending_client *ret_cl);
+
+#endif  // PENDING_CLIENTS_H
\ No newline at end of file
index d3d3e1e..1eedcd0 100644 (file)
  * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
  */
 
-#include <stdio.h>
 #include <barrelfish/barrelfish.h>
 #include <barrelfish/nameservice_client.h>
 #include <barrelfish/proc_mgmt_client.h>
 #include <barrelfish/spawn_client.h>
 #include <if/monitor_defs.h>
 #include <if/proc_mgmt_defs.h>
+#include <if/spawn_defs.h>
 
+#include "domain.h"
 #include "internal.h"
+#include "pending_clients.h"
 #include "spawnd_state.h"
 
 static void add_spawnd_handler(struct proc_mgmt_binding *b, coreid_t core_id,
@@ -46,14 +48,6 @@ static void add_spawnd_handler(struct proc_mgmt_binding *b, coreid_t core_id,
 
     debug_printf("Process manager bound with spawnd.%u on iref %u\n", core_id,
             iref);
-
-    err = spawnd_state_get_binding(core_id)->rpc_tx_vtbl.echo(
-            spawnd_state_get_binding(core_id),
-            SERVICE_BASENAME,
-            disp_get_current_core_id());
-    if (err_is_fail(err)) {
-        USER_PANIC_ERR(err, "spawnd echo request failed");
-    }
 }
 
 static void add_spawnd_handler_non_monitor(struct proc_mgmt_binding *b,
@@ -63,43 +57,252 @@ static void add_spawnd_handler_non_monitor(struct proc_mgmt_binding *b,
                  err_getstring(PROC_MGMT_ERR_NOT_MONITOR));
 }
 
-// static errval_t spawn_handler(struct proc_mgmt_binding *b,
-//                           coreid_t core,
-//                           const char *path,
-//                           const char *argvbuf,
-//                           size_t argvbytes,
-//                           const char *envbuf,
-//                           size_t envbytes,
-//                           uint8_t flags,
-//                           errval_t *err,
-//                           struct capref *domainid_cap)
-// {
-//     return LIB_ERR_NOT_IMPLEMENTED;
-// }
-
-// static errval_t span_handler(struct proc_mgmt_binding *b,
-//                          struct capref domainid_cap,
-//                          coreid_t core,
-//                          struct capref vroot,
-//                          struct capref disp_mem,
-//                          errval_t *err)
-// {
-//     return LIB_ERR_NOT_IMPLEMENTED;
-// }
-
-// static errval_t kill_handler(struct proc_mgmt_binding *b,
-//                          struct capref domainid_cap,
-//                          errval_t *err)
-// {
-//     return LIB_ERR_NOT_IMPLEMENTED;
-// }
+static void spawn_reply_handler(struct spawn_binding *b,
+                                struct capref domain_cap, errval_t spawn_err)
+{
+    struct pending_client cl;
+    errval_t err = pending_clients_release(domain_cap, &cl);
+    if (err_is_fail(err)) {
+        // This might be a kill request issued after a successful spawn/span
+        // followed by a local error in the process manager (see below). If that
+        // is the case, then we won't have a client, as it has already been
+        // released.
+        debug_printf("Unable to retrieve pending client based on domain cap "
+                     "returned by spawnd");
+        return;
+    }
+
+    errval_t resp_err;
+    switch (cl.type) {
+        case ClientType_Spawn:
+            err = spawn_err;
+            if (err_is_ok(spawn_err)) {
+                err = domain_spawn(domain_cap, cl.core_id);
+            }
+            resp_err = cl.b->tx_vtbl.spawn_response(cl.b, NOP_CONT, err,
+                                                     domain_cap);
+            break;
+
+        case ClientType_SpawnWithCaps:
+            err = spawn_err;
+            if (err_is_ok(spawn_err)) {
+                err = domain_spawn(domain_cap, cl.core_id);
+            }
+            resp_err = cl.b->tx_vtbl.spawn_with_caps_response(cl.b, NOP_CONT,
+                                                               err, domain_cap);
+            break;
+
+        case ClientType_Span:
+            err = spawn_err;
+            if (err_is_ok(spawn_err)) {
+                err = domain_span(domain_cap, cl.core_id);
+            }
+            resp_err = cl.b->tx_vtbl.span_response(cl.b, NOP_CONT, err);
+            break;
+
+        default:
+            // TODO(razvan): Handle the other cases, e.g. kill.
+            debug_printf("Unknown client type %u\n", cl.type);
+            return;
+    }
+
+    if (err_is_ok(spawn_err) && err_is_fail(err)) {
+        // Spawnd has successfully completed its end of the operation, but
+        // there's been an error in the process manager's book-keeping
+        // of domains. Therefore, if the request was a spawn or span one, spawnd
+        // needs to be asked to stop the dispatcher which it has just enqueued.
+        if (cl.type == ClientType_Spawn ||
+            cl.type == ClientType_SpawnWithCaps ||
+            cl.type == ClientType_Span) {
+            struct spawnd_state *state = spawnd_state_get(cl.core_id);
+            assert(state != NULL);
+            struct spawn_binding *spb = state->b;
+            assert(spb != NULL);
+
+            err = spb->tx_vtbl.kill_request(spb, NOP_CONT, domain_cap);
+            if (err_is_fail(err)) {
+                // XXX: How severe is this? Maybe we want something more
+                // assertive than logging an error message.
+                DEBUG_ERR(err, "failed to send kill request for dangling "
+                          "dispatcher");
+            }
+        }
+    }
+
+    if (err_is_fail(resp_err)) {
+        DEBUG_ERR(resp_err, "failed to send response to client");
+    }
+}
+
+static errval_t spawn_handler_common(struct proc_mgmt_binding *b,
+                                     enum ClientType type,
+                                     coreid_t core_id, const char *path,
+                                     const char *argvbuf, size_t argvbytes,
+                                     const char *envbuf, size_t envbytes,
+                                     struct capref inheritcn_cap,
+                                     struct capref argcn_cap, uint8_t flags,
+                                     struct capref *ret_domain_cap)
+{
+    assert(ret_domain_cap != NULL);
+
+    if (!spawnd_state_exists(core_id)) {
+        return PROC_MGMT_ERR_INVALID_SPAWND;
+    }
+
+    struct spawnd_state *state = spawnd_state_get(core_id);
+    assert(state != NULL);
+    struct spawn_binding *cl = state->b;
+    assert(cl != NULL);
+
+    struct capref domain_cap;
+    errval_t err = slot_alloc(&domain_cap);
+    if (err_is_fail(err)) {
+        DEBUG_ERR(err, "slot_alloc domain_cap");
+        return err_push(err, PROC_MGMT_ERR_CREATE_DOMAIN_CAP);
+    }
+    err = cap_retype(domain_cap, cap_procmng, 0, ObjType_Domain, 0, 1);
+    if (err_is_fail(err)) {
+        DEBUG_ERR(err, "cap_retype domain_cap");
+        return err_push(err, PROC_MGMT_ERR_CREATE_DOMAIN_CAP);
+    }
+
+    err = pending_clients_add(domain_cap, b, type, core_id);
+    if (err_is_fail(err)) {
+        DEBUG_ERR(err, "pending_clients_add");
+        return err;
+    }
+
+    cl->rx_vtbl.spawn_reply = spawn_reply_handler;
+    if (capref_is_null(inheritcn_cap) && capref_is_null(argcn_cap)) {
+        err = cl->tx_vtbl.spawn_request(cl, NOP_CONT, domain_cap, path, argvbuf,
+                                        argvbytes, envbuf, envbytes, flags);
+    } else {
+        err = cl->tx_vtbl.spawn_with_caps_request(cl, NOP_CONT, domain_cap,
+                                                  path, argvbuf, argvbytes,
+                                                  envbuf, envbytes,
+                                                  inheritcn_cap, argcn_cap,
+                                                  flags);
+    }
+    if (err_is_fail(err)) {
+        DEBUG_ERR(err, "sending spawn request");
+        pending_clients_release(domain_cap, NULL);
+        return err_push(err, PROC_MGMT_ERR_SPAWND_REQUEST);
+    }
+
+    return SYS_ERR_OK;
+}
+
+static void spawn_handler(struct proc_mgmt_binding *b, coreid_t core_id,
+                          const char *path, const char *argvbuf,
+                          size_t argvbytes, const char *envbuf, size_t envbytes,
+                          uint8_t flags)
+{
+    errval_t err, resp_err;
+    struct capref domain_cap;
+    err = spawn_handler_common(b, ClientType_Spawn, core_id, path, argvbuf,
+                               argvbytes, envbuf, envbytes, NULL_CAP, NULL_CAP,
+                               flags, &domain_cap);
+    if (err_is_ok(err)) {
+        // Will respond to client when we get the reply from spawnd.
+        return;
+    }
+
+    resp_err = b->tx_vtbl.spawn_response(b, NOP_CONT, err, NULL_CAP);
+    if (err_is_fail(resp_err)) {
+        DEBUG_ERR(resp_err, "failed to send spawn_response");
+    }
+}
+
+static void spawn_with_caps_handler(struct proc_mgmt_binding *b,
+                                    coreid_t core_id, const char *path,
+                                    const char *argvbuf, size_t argvbytes,
+                                    const char *envbuf, size_t envbytes,
+                                    struct capref inheritcn_cap,
+                                    struct capref argcn_cap, uint8_t flags)
+{
+    errval_t err, resp_err;
+    struct capref domain_cap;
+    err = spawn_handler_common(b, ClientType_SpawnWithCaps, core_id, path,
+                               argvbuf, argvbytes, envbuf, envbytes,
+                               inheritcn_cap, argcn_cap, flags, &domain_cap);
+    if (err_is_ok(err)) {
+        // Will respond to client when we get the reply from spawnd.
+        return;
+    }
+
+    resp_err = b->tx_vtbl.spawn_with_caps_response(b, NOP_CONT, err,
+                                                            NULL_CAP);
+    if (err_is_fail(resp_err)) {
+        DEBUG_ERR(resp_err, "failed to send spawn_with_caps_response");
+    }
+}
+
+static void span_handler(struct proc_mgmt_binding *b, struct capref domain_cap,
+                         coreid_t core_id, struct capref vroot,
+                         struct capref dispframe)
+{
+    errval_t err, resp_err;
+    err = domain_can_span(domain_cap, core_id);
+    if (err_is_fail(err)) {
+        goto respond_with_err;
+    }
+
+    if (!spawnd_state_exists(core_id)) {
+        err = PROC_MGMT_ERR_INVALID_SPAWND;
+        goto respond_with_err;
+    }
+
+    struct spawnd_state *state = spawnd_state_get(core_id);
+    assert(state != NULL);
+    struct spawn_binding *cl = state->b;
+    assert(cl != NULL);
+
+    err = pending_clients_add(domain_cap, b, ClientType_Span, core_id);
+    if (err_is_fail(err)) {
+        goto respond_with_err;
+    }
+
+    cl->rx_vtbl.spawn_reply = spawn_reply_handler;
+    err = cl->tx_vtbl.span_request(cl, NOP_CONT, domain_cap, vroot, dispframe);
+    if (err_is_ok(err)) {
+        // Will respond to client when we get the reply from spawnd.
+        return;
+    } else {
+        DEBUG_ERR(err, "sending span request");
+        pending_clients_release(domain_cap, NULL);
+        err = err_push(err, PROC_MGMT_ERR_SPAWND_REQUEST);
+    }
+
+respond_with_err:
+    resp_err = b->tx_vtbl.span_response(b, NOP_CONT, err);
+    if (err_is_fail(resp_err)) {
+        DEBUG_ERR(resp_err, "failed to send span_response");
+    }
+}
+
+static void kill_handler(struct proc_mgmt_binding *b, struct capref domain_cap)
+{
+    struct domain_entry *entry;
+    errval_t err = domain_get_by_cap(domain_cap, &entry);
+    if (err_is_ok(err)) {
+        domain_send_stop(entry);
+    }
+}
 
 static struct proc_mgmt_rx_vtbl monitor_vtbl = {
-    .add_spawnd = add_spawnd_handler
+    .add_spawnd           = add_spawnd_handler,
+    .spawn_call           = spawn_handler,
+    .spawn_with_caps_call = spawn_with_caps_handler,
+    .span_call            = span_handler,
+    .kill_call            = kill_handler
 };
 
 static struct proc_mgmt_rx_vtbl non_monitor_vtbl = {
-    .add_spawnd = add_spawnd_handler_non_monitor
+    .add_spawnd           = add_spawnd_handler_non_monitor,
+    .spawn_call           = spawn_handler,
+    .spawn_with_caps_call = spawn_with_caps_handler,
+    .span_call            = span_handler,
+    .kill_call            = kill_handler
 };
 
 static errval_t alloc_ep_for_monitor(struct capref *ep)
@@ -150,29 +353,6 @@ static void export_cb(void *st, errval_t err, iref_t iref)
     if (err_is_fail(err)) {
         USER_PANIC_ERR(err, "nameservice_register failed");
     }
-
-    // Try to create a few domains?
-    // TODO(razvan): Remove this.
-    size_t num_domains = 5;
-    struct capref domain_caps[num_domains];
-    for (size_t i = 1; i <= num_domains; ++i) {
-        err = slot_alloc(&domain_caps[i]);
-        if (err_is_fail(err)) {
-            USER_PANIC_ERR(err, "slot_alloc domain_cap");
-        }
-        err = cap_retype(domain_caps[i], cap_procmng, 0, ObjType_Domain, 0, 1);
-        if (err_is_fail(err)) {
-            USER_PANIC_ERR(err, "cap_retype domain_cap from cap_procmng");
-        }
-        struct capability ret;
-        err = debug_cap_identify(domain_caps[i], &ret);
-        if (err_is_fail(err)) {
-            USER_PANIC_ERR(err, "cap identify domain_cap");
-        }
-        debug_printf("Process manager successfully created domain { .coreid=%u,"
-                     " .core_local_id=%u } (%lu/%lu)\n", ret.u.domain.coreid,
-                     ret.u.domain.core_local_id, i, num_domains);
-    }
 }
 
 static errval_t connect_cb(void *st, struct proc_mgmt_binding *b)
diff --git a/usr/proc_mgmt/spawn_client.c b/usr/proc_mgmt/spawn_client.c
new file mode 100644 (file)
index 0000000..a37fe17
--- /dev/null
@@ -0,0 +1,135 @@
+/**
+ * \file
+ * \brief Spawn client for the process management service.
+ */
+
+/*
+ * Copyright (c) 2017, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#include "spawn_client.h"
+#include "spawnd_state.h"
+
+/**
+ * \brief Request the spawn daemon on a specific core to spawn a program
+ *
+ * \param coreid          Core ID on which to spawn the program
+ * \param path            Absolute path in the file system to an executable
+ *                        image suitable for the given core
+ * \param argv            Command-line arguments, NULL-terminated
+ * \param envp            Optional environment, NULL-terminated
+ *                        (pass NULL to inherit)
+ * \param inheritcn_cap   Cap to a CNode containing capabilities to be inherited
+ * \param argcn_cap       Cap to a CNode containing capabilities passed as
+ *                        arguments
+ * \param flags           Flags to spawn
+ * \param ret_domain_cap  If non-NULL, filled in with domain cap of new domain
+ *
+ * \bug flags are currently ignored
+ */
+errval_t spawn_with_caps(coreid_t core_id, const char *path,
+                         const char *argvbuf, size_t argvbytes,
+                         const char *envbuf, size_t envbytes,
+                         struct capref inheritcn_cap, struct capref argcn_cap,
+                         uint8_t flags, struct capref *ret_domain_cap)
+{
+    errval_t err, msgerr;
+
+    if (!spawnd_state_exists(core_id)) {
+        USER_PANIC("not connected to spawnd on the requested core");
+    }
+    struct spawnd_state *state = spawnd_state_get(core_id);
+    assert(state != NULL);
+    struct spawn_binding *cl = state->b;
+    assert(cl != NULL);
+
+    struct capref domain_cap;
+    err = slot_alloc(&domain_cap);
+    if (err_is_fail(err)) {
+       USER_PANIC_ERR(err, "slot_alloc domain_cap");
+    }
+    err = cap_retype(domain_cap, cap_procmng, 0, ObjType_Domain, 0, 1);
+       if (err_is_fail(err)) {
+           USER_PANIC_ERR(err, "cap_retype domain_cap from cap_procmng");
+       }
+
+    if (capref_is_null(inheritcn_cap) && capref_is_null(argcn_cap)) {
+        err = cl->rpc_tx_vtbl.spawn_proc_mgmt_domain(cl, domain_cap,
+                       path, argvbuf, argvbytes, envbuf, envbytes, flags, &msgerr);
+    } else {
+        err = cl->rpc_tx_vtbl.spawn_proc_mgmt_domain_with_caps(cl, domain_cap,
+                       path, argvbuf, argvbytes, envbuf, envbytes, inheritcn_cap,
+                       argcn_cap, flags, &msgerr);
+    }
+    if (err_is_fail(err)) {
+        USER_PANIC_ERR(err, "error sending spawn request");
+    } else if (err_is_fail(msgerr)) {
+        goto out;
+    }
+
+    if (ret_domain_cap != NULL) {
+        *ret_domain_cap = domain_cap;
+    }
+
+out:
+    return msgerr;
+}
+
+/**
+ * \brief Request the spawn daemon on a specific core to spawn a program
+ *
+ * \param coreid          Core ID on which to spawn the program
+ * \param path            Absolute path in the file system to an executable
+ *                        image suitable for the given core
+ * \param argv            Command-line arguments, NULL-terminated
+ * \param envp            Optional environment, NULL-terminated
+ *                        (pass NULL to inherit)
+ * \param inheritcn_cap   Cap to a CNode containing capabilities to be inherited
+ * \param argcn_cap       Cap to a CNode containing capabilities passed as
+ *                        arguments
+ * \param flags           Flags to spawn
+ * \param ret_domain_cap  If non-NULL, filled in with domain cap of new domain
+ *
+ * \bug flags are currently ignored
+ */
+errval_t spawn(coreid_t core_id, const char *path, const char *argvbuf,
+               size_t argvbytes, const char *envbuf, size_t envbytes,
+               uint8_t flags, struct capref *ret_domain_cap)
+{
+    return spawn_with_caps(core_id, path, argvbuf, argvbytes, envbuf, envbytes,
+                           NULL_CAP, NULL_CAP, flags, ret_domain_cap);
+}
+
+/**
+ * \brief Request the spawn daemon on a specific core to span an existing domain
+ *
+ * \param domain_cap Identifying capability for the domain to span
+ * \param core_id    Core ID on which to span
+ * \param vroot      Vspace root for the dispatcher to span
+ * \param dispframe  Frame for the dispatcher to span
+ */
+errval_t span(struct capref domain_cap, coreid_t core_id, struct capref vroot,
+              struct capref dispframe)
+{
+    errval_t err, msgerr;
+
+    if (!spawnd_state_exists(core_id)) {
+        USER_PANIC("not connected to spawnd on the requested core");
+    }
+    struct spawnd_state *state = spawnd_state_get(core_id);
+    assert(state != NULL);
+    struct spawn_binding *cl = state->b;
+    assert(cl != NULL);
+
+    err = cl->rpc_tx_vtbl.span(cl, domain_cap, vroot, dispframe, &msgerr);
+    if (err_is_fail(err)) {
+        USER_PANIC_ERR(err, "error sending span request");
+    }
+
+    return msgerr;
+}
diff --git a/usr/proc_mgmt/spawn_client.h b/usr/proc_mgmt/spawn_client.h
new file mode 100644 (file)
index 0000000..3193a0b
--- /dev/null
@@ -0,0 +1,31 @@
+/**
+ * \file
+ * \brief Spawn client for the process management service.
+ */
+
+/*
+ * Copyright (c) 2017, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#ifndef PROC_MGMT_SPAWN_CLIENT_H
+#define PROC_MGMT_SPAWN_CLIENT_H
+
+#include <barrelfish/barrelfish.h>
+
+errval_t spawn_with_caps(coreid_t core_id, const char *path,
+                            const char *argvbuf, size_t argvbytes,
+                            const char *envbuf, size_t envbytes,
+                            struct capref inheritcn_cap, struct capref argcn_cap,
+                            uint8_t flags, struct capref *ret_domain_cap);
+errval_t spawn(coreid_t core_id, const char *path, const char *argvbuf,
+                  size_t argvbytes, const char *envbuf, size_t envbytes,
+                  uint8_t flags, struct capref *ret_domain_cap);
+errval_t span(struct capref domain_cap, coreid_t core_id, struct capref vroot,
+                 struct capref dispframe);
+
+#endif  // PROC_MGMT_SPAWN_CLIENT_H
\ No newline at end of file
index f07d196..75f3022 100644 (file)
@@ -13,7 +13,7 @@
 
 #include "spawnd_state.h"
 
-static struct spawnd_state *spawnds[MAX_SPAWNDS];
+static struct spawnd_state *spawnds[MAX_COREID];
 
 errval_t spawnd_state_alloc(coreid_t core_id, struct spawn_binding *b)
 {
@@ -24,6 +24,7 @@ errval_t spawnd_state_alloc(coreid_t core_id, struct spawn_binding *b)
     }
 
     spawnds[core_id]->b = b;
+    spawnds[core_id]->core_id = core_id;
 
     return SYS_ERR_OK;
 }
@@ -40,7 +41,7 @@ inline bool spawnd_state_exists(coreid_t core_id)
     return spawnds[core_id] != NULL;
 }
 
-inline struct spawn_binding *spawnd_state_get_binding(coreid_t core_id)
+inline struct spawnd_state *spawnd_state_get(coreid_t core_id)
 {
-    return spawnds[core_id]->b;
+    return spawnds[core_id];
 }
index a14fd0f..ce5ae27 100644 (file)
 #include <if/spawn_defs.h>
 #include <barrelfish/barrelfish.h>
 
-// TODO(razvan): Use a hash map instead.
-#define MAX_SPAWNDS 256
-
 struct spawnd_state {
+       coreid_t core_id;
     struct spawn_binding *b;
+
     // TODO(razvan): will need more state here.
 };
 
 errval_t spawnd_state_alloc(coreid_t core_id, struct spawn_binding *b);
 void spawnd_state_free(coreid_t core_id);
 bool spawnd_state_exists(coreid_t core_id);
-struct spawn_binding *spawnd_state_get_binding(coreid_t core_id);
+struct spawnd_state *spawnd_state_get(coreid_t core_id);
 
 #endif  // SPAWND_STATE
index 3b9d173..f9473c5 100644 (file)
@@ -31,7 +31,9 @@ struct ps_entry {
     char *argv[MAX_CMDLINE_ARGS];
     char *argbuf;
     size_t argbytes;
-    struct capref rootcn_cap, dcb;
+    struct capref domain_cap;
+    struct capref rootcn_cap;
+    struct capref dcb;
     struct cnoderef rootcn;
     uint8_t exitcode;
     enum ps_status status;
index 0e9f700..66102ca 100644 (file)
 #include "ps.h"
 
 
-static errval_t spawn(const char *path, char *const argv[], const char *argbuf,
-                      size_t argbytes, char *const envp[],
-                      struct capref inheritcn_cap, struct capref argcn_cap,
-                      uint8_t flags, domainid_t *domainid)
+static errval_t spawn(struct capref domain_cap, const char *path,
+                      char *const argv[], const char *argbuf, size_t argbytes,
+                      char *const envp[], struct capref inheritcn_cap,
+                      struct capref argcn_cap, uint8_t flags,
+                      domainid_t *domainid)
 {
     errval_t err, msgerr;
 
@@ -142,7 +143,17 @@ static errval_t spawn(const char *path, char *const argv[], const char *argbuf,
     src.slot = TASKCN_SLOT_PERF_MON;
     err = cap_copy(dest, src);
     if (err_is_fail(err)) {
-        return err_push(err, INIT_ERR_COPY_PERF_MON);
+        return err_push(err, SPAWN_ERR_COPY_PERF_MON);
+    }
+
+    if (!capref_is_null(domain_cap)) {
+        // Pass over the domain cap.
+        dest.cnode = si.taskcn;
+        dest.slot = TASKCN_SLOT_DOMAINID;
+        err = cap_copy(dest, domain_cap);
+        if (err_is_fail(err)) {
+            return err_push(err, SPAWN_ERR_COPY_DOMAIN_CAP);
+        }
     }
 
     /* run the domain */
@@ -177,6 +188,7 @@ static errval_t spawn(const char *path, char *const argv[], const char *argbuf,
     err = cap_copy(pe->dcb, si.dcb);
     assert(err_is_ok(err));
     pe->status = PS_STATUS_RUNNING;
+    pe->domain_cap = domain_cap;
     err = ps_allocate(pe, domainid);
     if(err_is_fail(err)) {
         free(pe);
@@ -240,7 +252,8 @@ struct pending_spawn_response {
     domainid_t domainid;
 };
 
-static errval_t spawn_with_caps_common(const char *path, const char *argbuf,
+static errval_t spawn_with_caps_common(struct capref domain_cap,
+                                       const char *path, const char *argbuf,
                                        size_t argbytes, const char *envbuf,
                                        size_t envbytes,
                                        struct capref inheritcn_cap,
@@ -288,8 +301,8 @@ static errval_t spawn_with_caps_common(const char *path, const char *argbuf,
     strcpy(npath, path);
     vfs_path_normalise(npath);
 
-    err = spawn(npath, argv, argbuf, argbytes, envp, inheritcn_cap, argcn_cap,
-                flags, domainid);
+    err = spawn(domain_cap, npath, argv, argbuf, argbytes, envp, inheritcn_cap,
+                argcn_cap, flags, domainid);
     // XXX: do we really want to delete the inheritcn and the argcn here? iaw:
     // do we copy these somewhere? -SG
     if (!capref_is_null(inheritcn_cap)) {
@@ -316,8 +329,9 @@ static errval_t spawn_with_caps_handler(struct spawn_binding *b, const char *pat
     struct capref inheritcn_cap, struct capref argcn_cap, uint8_t flags,
     errval_t *err, spawn_domainid_t *domain_id)
 {
-    *err = spawn_with_caps_common(path, argvbuf, argvbytes, envbuf, envbytes,
-                                 inheritcn_cap, argcn_cap, flags, domain_id);
+    *err = spawn_with_caps_common(NULL_CAP, path, argvbuf, argvbytes, envbuf,
+                                  envbytes, inheritcn_cap, argcn_cap, flags,
+                                  domain_id);
     return SYS_ERR_OK;
 }
 
@@ -325,11 +339,180 @@ static errval_t spawn_handler(struct spawn_binding *b, const char *path,
     const char *argvbuf, size_t argvbytes, const char *envbuf, size_t envbytes,
     uint8_t flags, errval_t *err, spawn_domainid_t *domain_id)
 {
-    *err = spawn_with_caps_common(path, argvbuf, argvbytes, envbuf, envbytes,
-                                 NULL_CAP, NULL_CAP, flags, domain_id);
+    *err = spawn_with_caps_common(NULL_CAP, path, argvbuf, argvbytes, envbuf,
+                                  envbytes, NULL_CAP, NULL_CAP, flags,
+                                  domain_id);
     return SYS_ERR_OK;
 }
 
+static void spawn_with_caps_request_handler(struct spawn_binding *b,
+                                            struct capref domain_cap,
+                                            const char *path,
+                                            const char *argvbuf,
+                                            size_t argvbytes,
+                                            const char *envbuf,
+                                            size_t envbytes,
+                                            struct capref inheritcn_cap,
+                                            struct capref argcn_cap,
+                                            uint8_t flags)
+{
+    spawn_domainid_t dummy_domain_id;
+    errval_t err = spawn_with_caps_common(domain_cap, path, argvbuf, argvbytes,
+                                          envbuf, envbytes, inheritcn_cap,
+                                          argcn_cap, flags, &dummy_domain_id);
+    errval_t reply_err = b->tx_vtbl.spawn_reply(b, NOP_CONT, domain_cap, err);
+    if (err_is_fail(reply_err)) {
+        DEBUG_ERR(err, "failed to send spawn_reply");
+    }
+}
+
+static void spawn_request_handler(struct spawn_binding *b,
+                                  struct capref domain_cap, const char *path,
+                                  const char *argvbuf, size_t argvbytes,
+                                  const char *envbuf, size_t envbytes,
+                                  uint8_t flags)
+{
+    spawn_domainid_t dummy_domain_id;
+    errval_t err = spawn_with_caps_common(domain_cap, path, argvbuf, argvbytes,
+                                          envbuf, envbytes, NULL_CAP, NULL_CAP,
+                                          flags, &dummy_domain_id);
+    errval_t reply_err = b->tx_vtbl.spawn_reply(b, NOP_CONT, domain_cap, err);
+    if (err_is_fail(reply_err)) {
+        DEBUG_ERR(err, "failed to send spawn_reply");
+    }
+}
+
+static void span_request_handler(struct spawn_binding *b,
+                                 struct capref domain_cap, struct capref vroot,
+                                 struct capref dispframe)
+{
+    struct spawninfo si;
+    errval_t err, mon_err, reply_err;
+
+    memset(&si, 0, sizeof(si));
+
+    debug_printf("Spanning domain to core %d\n", disp_get_core_id());
+
+    // Span domain
+    err = spawn_span_domain(&si, vroot, dispframe);
+    if (err_is_fail(err)) {
+        err = err_push(err, SPAWN_ERR_SPAN);
+        goto reply;
+    }
+
+    // Set connection to monitor.
+    struct monitor_blocking_binding *mrpc = get_monitor_blocking_binding();
+    struct capref monep;
+    err = slot_alloc(&monep);
+    if (err_is_fail(err)) {
+        err = err_push(err, SPAWN_ERR_MONEP_SLOT_ALLOC);
+        goto reply;
+    }
+    err = mrpc->rpc_tx_vtbl.alloc_monitor_ep(mrpc, &mon_err, &monep);
+    if (err_is_ok(err)) {
+        err = mon_err;
+    }
+    if (err_is_fail(err)) {
+        err = err_push(err, SPAWN_ERR_MONITOR_CLIENT);
+        goto reply;
+    }
+
+    /* copy connection into the new domain */
+    struct capref destep = {
+        .cnode = si.taskcn,
+        .slot  = TASKCN_SLOT_MONITOREP,
+    };
+    err = cap_copy(destep, monep);
+    if (err_is_fail(err)) {
+        spawn_free(&si);
+        cap_destroy(monep);
+        err = err_push(err, SPAWN_ERR_MONITOR_CLIENT);
+        goto reply;
+    }
+
+    err = cap_destroy(monep);
+    if (err_is_fail(err)) {
+        err = err_push(err, SPAWN_ERR_MONITOR_CLIENT);
+        goto reply;
+    }
+
+    /* give the perfmon capability */
+    struct capref dest, src;
+    dest.cnode = si.taskcn;
+    dest.slot = TASKCN_SLOT_PERF_MON;
+    src.cnode = cnode_task;
+    src.slot = TASKCN_SLOT_PERF_MON;
+    err = cap_copy(dest, src);
+    if (err_is_fail(err)) {
+        err = err_push(err, SPAWN_ERR_COPY_PERF_MON);
+        goto reply;
+    }
+
+    // Pass over the domain cap.
+    dest.cnode = si.taskcn;
+    dest.slot = TASKCN_SLOT_DOMAINID;
+    err = cap_copy(dest, domain_cap);
+    if (err_is_fail(err)) {
+        err = err_push(err, SPAWN_ERR_COPY_DOMAIN_CAP);
+        goto reply;
+    }
+
+    // Make runnable
+    err = spawn_run(&si);
+    if (err_is_fail(err)) {
+        err = err_push(err, SPAWN_ERR_RUN);
+        goto reply;
+    }
+
+    // Allocate an id for this dispatcher.
+    struct ps_entry *pe = malloc(sizeof(struct ps_entry));
+    assert(pe != NULL);
+    memset(pe, 0, sizeof(struct ps_entry));
+    /*
+     * NB: It's important to keep a copy of the DCB *and* the root
+     * CNode around.  We need to revoke both (in the right order, see
+     * kill_domain() below), so that we ensure no one else is
+     * referring to the domain's CSpace anymore. Especially the loop
+     * created by placing rootcn into its own address space becomes a
+     * problem here.
+     */
+    // TODO(razvan): The following code is here to comply with spawn().
+    err = slot_alloc(&pe->rootcn_cap);
+    assert(err_is_ok(err));
+    err = cap_copy(pe->rootcn_cap, si.rootcn_cap);
+    pe->rootcn = si.rootcn;
+    assert(err_is_ok(err));
+    err = slot_alloc(&pe->dcb);
+    assert(err_is_ok(err));
+    err = cap_copy(pe->dcb, si.dcb);
+    assert(err_is_ok(err));
+    pe->status = PS_STATUS_RUNNING;
+    pe->domain_cap = domain_cap;
+    domainid_t domainid;
+    err = ps_allocate(pe, &domainid);
+    if(err_is_fail(err)) {
+        free(pe);
+    }
+
+    // Cleanup
+    err = spawn_free(&si);
+    if (err_is_fail(err)) {
+        err = err_push(err, SPAWN_ERR_FREE);
+    }
+
+reply:
+    reply_err = b->tx_vtbl.spawn_reply(b, NOP_CONT, domain_cap, err);
+    if (err_is_fail(reply_err)) {
+        DEBUG_ERR(err, "failed to send spawn_reply");
+    }
+}
+
+static void kill_request_handler(struct spawn_binding *b,
+                                 struct capref domain_cap)
+{
+    debug_printf("kill_request_handler: NYI\n");
+}
+
 /**
  * \brief Removes a zombie domain.
  */
@@ -530,18 +713,16 @@ static void dump_capabilities_handler(struct spawn_binding *b, domainid_t domain
     }
 }
 
-// TODO(razvan): This is just used to test that the process manager can connect
-// to arbitrary spawnds; maybe remove it soon.
-static errval_t echo_handler(struct spawn_binding *b, const char *sender_name,
-                             coreid_t sender_core)
-{
-    debug_printf("spawnd ECHO from: %s.%u\n", sender_name, sender_core);
-    return SYS_ERR_OK;
-}
-
 static struct spawn_rx_vtbl rx_vtbl = {
     // .spawn_domain_call = spawn_handler,
     // .spawn_domain_with_caps_call = spawn_with_caps_handler,
+
+    // Async messages for the process manager.
+    .spawn_request           = spawn_request_handler,
+    .spawn_with_caps_request = spawn_with_caps_request_handler,
+    .span_request            = span_request_handler,
+    .kill_request            = kill_request_handler,
+
     .use_local_memserv_call = use_local_memserv_handler,
     .kill_call = kill_handler,
     .exit_call = exit_handler,
@@ -554,7 +735,6 @@ static struct spawn_rx_vtbl rx_vtbl = {
 static struct spawn_rpc_rx_vtbl rpc_rx_vtbl = {
     .spawn_domain_call = spawn_handler,
     .spawn_domain_with_caps_call = spawn_with_caps_handler,
-    .echo_call = echo_handler
     // .use_local_memserv_call = use_local_memserv_handler,
     // .kill_call = kill_handler,
     // .exit_call = exit_handler,