d2c6c60f0b8d30253030feedad5f034202fce52c
[barrelfish] / usr / proc_mgmt / service.c
1 /**
2  * \file
3  * \brief Process management service.
4  */
5
6 /*
7  * Copyright (c) 2017, ETH Zurich.
8  * All rights reserved.
9  *
10  * This file is distributed under the terms in the attached LICENSE file.
11  * If you do not find this file, copies can be found by writing to:
12  * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
13  */
14
15 #include <barrelfish/barrelfish.h>
16 #include <barrelfish/nameservice_client.h>
17 #include <barrelfish/proc_mgmt_client.h>
18 #include <barrelfish/spawn_client.h>
19 #include <if/monitor_defs.h>
20 #include <if/proc_mgmt_defs.h>
21 #include <if/spawn_defs.h>
22
23 #include "domain.h"
24 #include "internal.h"
25 #include "pending_clients.h"
26 #include "spawnd_state.h"
27
28 /**
29  * \brief Handler for message add_spawnd, for the local monitor binding.
30  */
31 static void add_spawnd_handler(struct proc_mgmt_binding *b, coreid_t core_id,
32                                iref_t iref)
33 {
34     if (spawnd_state_exists(core_id)) {
35         DEBUG_ERR(PROC_MGMT_ERR_SPAWND_EXISTS, "spawnd_state_exists");
36         return;
37     }
38
39     // Bind with the spawnd.
40     struct spawn_binding *spawnb;
41     errval_t err = spawn_bind_iref(iref, &spawnb);
42     if (err_is_fail(err)) {
43         DEBUG_ERR(err, "spawn_bind_iref");
44         return;
45     }
46
47     err = spawnd_state_alloc(core_id, spawnb);
48     if (err_is_fail(err)) {
49         DEBUG_ERR(err, "spawnd_state_alloc");
50     }
51
52     debug_printf("Process manager bound with spawnd.%u on iref %u\n", core_id,
53             iref);
54 }
55
56 /**
57  * \brief Handler for message add_spawnd, for non-monitor bindings.
58  */
59 static void add_spawnd_handler_non_monitor(struct proc_mgmt_binding *b,
60                                            coreid_t core_id, iref_t iref)
61 {
62     // debug_printf("Ignoring add_spawnd call: %s\n",
63     //              err_getstring(PROC_MGMT_ERR_NOT_MONITOR));
64 }
65
66 static bool cleanup_request_sender(struct msg_queue_elem *m);
67
68 /**
69  * General-purpose handler for replies from spawnd.
70  */
71 static void spawn_reply_handler(struct spawn_binding *b, errval_t spawn_err)
72 {
73     struct pending_client *cl =
74             (struct pending_client*) spawnd_state_dequeue_recv(b->st);
75
76     struct pending_spawn *spawn = NULL;
77     struct pending_span *span = NULL;
78     struct pending_kill_cleanup *kc = NULL;
79
80     struct domain_entry *entry;
81     
82     errval_t err, resp_err;
83
84     switch (cl->type) {
85         case ClientType_Spawn:
86         case ClientType_SpawnWithCaps:
87             spawn = (struct pending_spawn*) cl->st;
88             err = spawn_err;
89             if (err_is_ok(spawn_err)) {
90                 err = domain_spawn(spawn->cap_node, spawn->core_id);
91                 if (cl->type == ClientType_Spawn) {
92                     resp_err = cl->b->tx_vtbl.spawn_response(cl->b, NOP_CONT,
93                             err, spawn->cap_node->domain_cap);
94                 } else {
95                     resp_err = cl->b->tx_vtbl.spawn_with_caps_response(cl->b,
96                             NOP_CONT, err, spawn->cap_node->domain_cap);
97                 }
98             }
99
100             free(spawn);
101             break;
102
103         case ClientType_Span:
104             span = (struct pending_span*) cl->st;
105             entry = span->entry;
106             if (entry->status == DOMAIN_STATUS_RUNNING) {
107                 resp_err = cl->b->tx_vtbl.span_response(cl->b, NOP_CONT,
108                                                         spawn_err);
109             }
110
111             free(span);
112             break;
113
114         case ClientType_Cleanup:
115             kc = (struct pending_kill_cleanup*) cl->st;
116             entry = kc->entry;
117
118             assert(entry->num_spawnds_resources > 0);
119             assert(entry->status != DOMAIN_STATUS_CLEANED);
120
121             --entry->num_spawnds_resources;
122             if (entry->num_spawnds_resources == 0) {
123                 entry->status = DOMAIN_STATUS_CLEANED;
124
125                 // At this point, the domain exists in state CLEANED for history
126                 // reasons. For instance, if some other domain issues a wait
127                 // call for this one, the process manager can return the exit
128                 // status directly. At some point, however, we might want to
129                 // just clean up the domain entry and recycle the domain cap.
130             }
131
132             free(kc);
133             break;
134
135         case ClientType_Kill:
136         case ClientType_Exit:
137             kc = (struct pending_kill_cleanup*) cl->st;
138             entry = kc->entry;
139
140             assert(entry->num_spawnds_running > 0);
141             assert(entry->status != DOMAIN_STATUS_STOPPED);
142
143             --entry->num_spawnds_running;
144
145             if (entry->num_spawnds_running == 0) {
146                 entry->status = DOMAIN_STATUS_STOPPED;
147
148                 if (cl->type == ClientType_Kill) {
149                     entry->exit_status = EXIT_STATUS_KILLED;
150                     resp_err = cl->b->tx_vtbl.kill_response(cl->b, NOP_CONT,
151                                                             spawn_err);
152                 }
153
154                 struct domain_waiter *waiter = entry->waiters;
155                 while (waiter != NULL) {
156                     waiter->b->tx_vtbl.wait_response(waiter->b, NOP_CONT,
157                                                      SYS_ERR_OK,
158                                                      entry->exit_status);
159                     struct domain_waiter *tmp = waiter;
160                     waiter = waiter->next;
161                     free(tmp);
162                 }
163
164                 for (coreid_t i = 0; i < MAX_COREID; ++i) {
165                     if (entry->spawnds[i] == NULL) {
166                         continue;
167                     }
168
169                     struct spawn_binding *spb = entry->spawnds[i]->b;
170
171                     struct pending_kill_cleanup *cleanup =
172                             (struct pending_kill_cleanup*) malloc(
173                                     sizeof(struct pending_kill_cleanup));
174                     cleanup->b = spb;
175                     cleanup->domain_cap = kc->domain_cap;
176                     cleanup->entry = entry;
177
178                     struct pending_client *cleanup_cl =
179                             (struct pending_client*) malloc(
180                                     sizeof(struct pending_client));
181                     cleanup_cl->b = cl->b;
182                     cleanup_cl->type = ClientType_Cleanup;
183                     cleanup_cl->st = cleanup;
184
185                     struct msg_queue_elem *msg = (struct msg_queue_elem*) malloc(
186                             sizeof(struct msg_queue_elem));
187                     msg->st = cleanup_cl;
188                     msg->cont = cleanup_request_sender;
189
190                     err = spawnd_state_enqueue_send(entry->spawnds[i], msg);
191
192                     if (err_is_fail(err)) {
193                         DEBUG_ERR(err, "enqueuing cleanup request");
194                         free(cleanup);
195                         free(cleanup_cl);
196                         free(msg);
197                     }
198                 }
199             }
200
201             free(kc);
202             break;
203
204         default:
205             USER_PANIC("Unknown client type in spawn_reply_handler: %u\n",
206                        cl->type);
207     }
208
209     free(cl);
210 }
211
212 /**
213  * \brief Handler for sending spawn requests.
214  */
215 static bool spawn_request_sender(struct msg_queue_elem *m)
216 {
217     struct pending_client *cl = (struct pending_client*) m->st;
218     struct pending_spawn *spawn = (struct pending_spawn*) cl->st;
219     spawn->b->rx_vtbl.spawn_reply = spawn_reply_handler;
220
221     errval_t err;
222     bool with_caps = !(capref_is_null(spawn->inheritcn_cap) &&
223                        capref_is_null(spawn->argcn_cap));
224     if (with_caps) {
225         err = spawn->b->tx_vtbl.spawn_with_caps_request(spawn->b, NOP_CONT,
226                                                         cap_procmng,
227                                                         spawn->cap_node->domain_cap,
228                                                         spawn->path,
229                                                         spawn->argvbuf,
230                                                         spawn->argvbytes,
231                                                         spawn->envbuf,
232                                                         spawn->envbytes,
233                                                         spawn->inheritcn_cap,
234                                                         spawn->argcn_cap,
235                                                         spawn->flags);
236     } else {
237         err = spawn->b->tx_vtbl.spawn_request(spawn->b, NOP_CONT, cap_procmng,
238                                               spawn->cap_node->domain_cap,
239                                               spawn->path, spawn->argvbuf,
240                                               spawn->argvbytes, spawn->envbuf,
241                                               spawn->envbytes, spawn->flags);
242     }
243
244     if (err_is_fail(err)) {
245         if (err_no(err) == FLOUNDER_ERR_TX_BUSY) {
246             return false;
247         } else {
248             USER_PANIC_ERR(err, "sending spawn request");
249         }
250     }
251
252     free(m);
253
254     return true;
255 }
256
257 /**
258  * \brief Handler for sending span requests.
259  */
260 static bool span_request_sender(struct msg_queue_elem *m)
261 {
262     struct pending_client *cl = (struct pending_client*) m->st;
263     struct pending_span *span = (struct pending_span*) cl->st;
264
265     errval_t err;
266     span->b->rx_vtbl.spawn_reply = spawn_reply_handler;
267     err = span->b->tx_vtbl.span_request(span->b, NOP_CONT, cap_procmng,
268                                         span->domain_cap, span->vroot,
269                                         span->dispframe);
270
271     if (err_is_fail(err)) {
272         if (err_no(err) == FLOUNDER_ERR_TX_BUSY) {
273             return false;
274         } else {
275             USER_PANIC_ERR(err, "sending span request");
276         }
277     }
278
279     free(m);
280
281     return true;
282 }
283
284 /**
285  * \brief Handler for sending kill requests.
286  */
287 static bool kill_request_sender(struct msg_queue_elem *m)
288 {
289     struct pending_client *cl = (struct pending_client*) m->st;
290     struct pending_kill_cleanup *kill = (struct pending_kill_cleanup*) cl->st;
291
292     errval_t err;
293     kill->b->rx_vtbl.spawn_reply = spawn_reply_handler;
294     err = kill->b->tx_vtbl.kill_request(kill->b, NOP_CONT, cap_procmng,
295                                         kill->domain_cap);
296
297     if (err_is_fail(err)) {
298         if (err_no(err) == FLOUNDER_ERR_TX_BUSY) {
299             return false;
300         } else {
301             USER_PANIC_ERR(err, "sending kill request");
302         }
303     }
304
305     free(m);
306
307     return true;
308 }
309
310 /**
311  * \brief Handler for sending cleanup requests.
312  */
313 static bool cleanup_request_sender(struct msg_queue_elem *m)
314 {
315     struct pending_client *cl = (struct pending_client*) m->st;
316     struct pending_kill_cleanup *cleanup = (struct pending_kill_cleanup*) cl->st;
317
318     errval_t err;
319     cleanup->b->rx_vtbl.spawn_reply = spawn_reply_handler;
320     err = cleanup->b->tx_vtbl.cleanup_request(cleanup->b, NOP_CONT,
321                                               cap_procmng,
322                                               cleanup->domain_cap);
323
324     if (err_is_fail(err)) {
325         if (err_no(err) == FLOUNDER_ERR_TX_BUSY) {
326             return false;
327         } else {
328             USER_PANIC_ERR(err, "sending cleanup request");
329         }
330     }
331
332     free(m);
333
334     return true;
335 }
336
337 /**
338  * \brief Common bits of the spawn and spawn_with_caps handlers.
339  */
340 static errval_t spawn_handler_common(struct proc_mgmt_binding *b,
341                                      enum ClientType type,
342                                      coreid_t core_id, const char *path,
343                                      const char *argvbuf, size_t argvbytes,
344                                      const char *envbuf, size_t envbytes,
345                                      struct capref inheritcn_cap,
346                                      struct capref argcn_cap, uint8_t flags)
347 {
348     if (!spawnd_state_exists(core_id)) {
349         return PROC_MGMT_ERR_INVALID_SPAWND;
350     }
351
352     struct spawnd_state *spawnd = spawnd_state_get(core_id);
353     assert(spawnd != NULL);
354     struct spawn_binding *cl = spawnd->b;
355     assert(cl != NULL);
356
357     errval_t err;
358     if (domain_should_refill_caps()) {
359         err = domain_prealloc_caps();
360         if (err_is_fail(err)) {
361             return err_push(err, PROC_MGMT_ERR_CREATE_DOMAIN_CAP);
362         }
363     }
364
365     struct domain_cap_node *cap_node = next_cap_node();
366
367     struct pending_spawn *spawn = (struct pending_spawn*) malloc(
368             sizeof(struct pending_spawn));
369     spawn->cap_node = cap_node;
370     // spawn->domain_cap = domain_cap;
371     spawn->b = cl;
372     spawn->core_id = core_id;
373     spawn->path = path;
374     spawn->argvbuf = argvbuf;
375     spawn->argvbytes = argvbytes;
376     spawn->envbuf = envbuf;
377     spawn->envbytes = envbytes;
378     spawn->inheritcn_cap = inheritcn_cap;
379     spawn->argcn_cap = argcn_cap;
380     spawn->flags = flags;
381
382     struct pending_client *spawn_cl = (struct pending_client*) malloc(
383             sizeof(struct pending_client));
384     spawn_cl->b = b;
385     spawn_cl->type = type;
386     spawn_cl->st = spawn;
387
388     struct msg_queue_elem *msg = (struct msg_queue_elem*) malloc(
389             sizeof(struct msg_queue_elem));
390     msg->st = spawn_cl;
391     msg->cont = spawn_request_sender;
392
393     err = spawnd_state_enqueue_send(spawnd, msg);
394     if (err_is_fail(err)) {
395         DEBUG_ERR(err, "enqueuing spawn request");
396         free(spawn);
397         free(spawn_cl);
398         free(msg);
399     }
400
401     return SYS_ERR_OK;
402 }
403
404 /**
405  * \brief Handler for rpc spawn.
406  */
407 static void spawn_handler(struct proc_mgmt_binding *b, coreid_t core_id,
408                           const char *path, const char *argvbuf,
409                           size_t argvbytes, const char *envbuf, size_t envbytes,
410                           uint8_t flags)
411 {
412     errval_t err, resp_err;
413     err = spawn_handler_common(b, ClientType_Spawn, core_id, path, argvbuf,
414                                argvbytes, envbuf, envbytes, NULL_CAP, NULL_CAP,
415                                flags);
416
417     if (err_is_fail(err)) {
418         resp_err = b->tx_vtbl.spawn_response(b, NOP_CONT, err, NULL_CAP);
419         if (err_is_fail(resp_err)) {
420             DEBUG_ERR(resp_err, "failed to send spawn_response");
421         }
422     }
423 }
424
425 /**
426  * \brief Handler for rpc spawn_with_caps.
427  */
428 static void spawn_with_caps_handler(struct proc_mgmt_binding *b,
429                                     coreid_t core_id, const char *path,
430                                     const char *argvbuf, size_t argvbytes,
431                                     const char *envbuf, size_t envbytes,
432                                     struct capref inheritcn_cap,
433                                     struct capref argcn_cap, uint8_t flags)
434 {
435     errval_t err, resp_err;
436     err = spawn_handler_common(b, ClientType_SpawnWithCaps, core_id, path,
437                                argvbuf, argvbytes, envbuf, envbytes,
438                                inheritcn_cap, argcn_cap, flags);
439     if (err_is_ok(err)) {
440         // Will respond to client when we get the reply from spawnd.
441         return;
442     }
443
444     resp_err = b->tx_vtbl.spawn_with_caps_response(b, NOP_CONT, err,
445                                                             NULL_CAP);
446     if (err_is_fail(resp_err)) {
447         DEBUG_ERR(resp_err, "failed to send spawn_with_caps_response");
448     }
449 }
450
451 /**
452  * \brief Handler for rpc span.
453  */
454 static void span_handler(struct proc_mgmt_binding *b, struct capref domain_cap,
455                          coreid_t core_id, struct capref vroot,
456                          struct capref dispframe)
457 {
458     errval_t err, resp_err;
459     struct domain_entry *entry = NULL;
460     err = domain_get_by_cap(domain_cap, &entry);
461     if (err_is_fail(err)) {
462         goto respond_with_err;
463     }
464
465     assert(entry != NULL);
466     if (entry->status != DOMAIN_STATUS_RUNNING) {
467         err = PROC_MGMT_ERR_DOMAIN_NOT_RUNNING;
468         goto respond_with_err;
469     }
470
471     if (entry->spawnds[core_id] != NULL) {
472         // TODO(razvan): Maybe we want to allow the same domain to span multiple
473         // dispatchers onto the same core?
474         err = PROC_MGMT_ERR_ALREADY_SPANNED;
475         goto respond_with_err;
476     }
477
478     if (!spawnd_state_exists(core_id)) {
479         err = PROC_MGMT_ERR_INVALID_SPAWND;
480         goto respond_with_err;
481     }
482
483     struct spawnd_state *spawnd = spawnd_state_get(core_id);
484     assert(spawnd != NULL);
485     struct spawn_binding *cl = spawnd->b;
486     assert(cl != NULL);
487
488     struct pending_span *span = (struct pending_span*) malloc(
489             sizeof(struct pending_span));
490     span->domain_cap = domain_cap;
491     span->entry = entry;
492     span->b = cl;
493     span->core_id = core_id;
494     span->vroot = vroot;
495     span->dispframe = dispframe;
496
497     struct pending_client *span_cl = (struct pending_client*) malloc(
498             sizeof(struct pending_client));
499     span_cl->b = b;
500     span_cl->type = ClientType_Span;
501     span_cl->st = span;
502
503     struct msg_queue_elem *msg = (struct msg_queue_elem*) malloc(
504             sizeof(struct msg_queue_elem));
505     msg->st = span_cl;
506     msg->cont = span_request_sender;
507
508     err = spawnd_state_enqueue_send(spawnd, msg);
509
510     if (err_is_fail(err)) {
511         DEBUG_ERR(err, "enqueuing span request");
512         free(span);
513         free(span_cl);
514         free(msg);
515     }
516
517 respond_with_err:
518     resp_err = b->tx_vtbl.span_response(b, NOP_CONT, err);
519     if (err_is_fail(resp_err)) {
520         DEBUG_ERR(resp_err, "failed to send span_response");
521     }
522 }
523
524 /**
525  * \brief Common bits of the kill and exit handlers.
526  */
527 static errval_t kill_handler_common(struct proc_mgmt_binding *b,
528                                     struct capref domain_cap,
529                                     enum ClientType type,
530                                     uint8_t exit_status)
531 {
532     struct domain_entry *entry;
533     errval_t err = domain_get_by_cap(domain_cap, &entry);
534     if (err_is_fail(err)) {
535         return err;
536     }
537
538     entry->exit_status = exit_status;
539     domain_stop_pending(entry);
540
541     for (coreid_t i = 0; i < MAX_COREID; ++i) {
542         if (entry->spawnds[i] == NULL) {
543             continue;
544         }
545
546         struct spawn_binding *spb = entry->spawnds[i]->b;
547
548         struct pending_kill_cleanup *cmd = (struct pending_kill_cleanup*) malloc(
549                 sizeof(struct pending_kill_cleanup));
550         cmd->domain_cap = domain_cap;
551         cmd->entry = entry;
552         cmd->b = spb;
553
554         struct pending_client *cl = (struct pending_client*) malloc(
555                 sizeof(struct pending_client));
556         cl->b = b;
557         cl->type = type;
558         cl->st = cmd;
559
560         struct msg_queue_elem *msg = (struct msg_queue_elem*) malloc(
561                 sizeof(struct msg_queue_elem));
562         msg->st = cl;
563         msg->cont = kill_request_sender;
564
565         err = spawnd_state_enqueue_send(entry->spawnds[i], msg);
566         if (err_is_fail(err)) {
567             DEBUG_ERR(err, "enqueuing kill request");
568             free(cmd);
569             free(cl);
570             free(msg);
571         }
572     }
573
574     return SYS_ERR_OK;
575 }
576
577 /**
578  * \brief Handler for rpc kill.
579  */
580 static void kill_handler(struct proc_mgmt_binding *b,
581                          struct capref victim_domain_cap)
582 {
583     errval_t err = kill_handler_common(b, victim_domain_cap, ClientType_Kill,
584                                        EXIT_STATUS_KILLED);
585     if (err_is_fail(err)) {
586         errval_t resp_err = b->tx_vtbl.kill_response(b, NOP_CONT, err);
587         if (err_is_fail(resp_err)) {
588             DEBUG_ERR(resp_err, "failed to send kill_response");
589         }
590     }
591 }
592
593 /**
594  * \brief Handler for message exit.
595  */
596 static void exit_handler(struct proc_mgmt_binding *b, struct capref domain_cap,
597                          uint8_t exit_status)
598 {
599     errval_t err = kill_handler_common(b, domain_cap, ClientType_Exit,
600                                        exit_status);
601     if (err_is_fail(err)) {
602         DEBUG_ERR(err, "processing exit_handler for requesting domain, exit "
603                   "code %u", exit_status);
604     }
605     // Error or not, there's no client to respond to anymore.
606 }
607
608 /**
609  * \brief Handler for rpc wait.
610  */
611 static void wait_handler(struct proc_mgmt_binding *b, struct capref domain_cap)
612 {
613     errval_t err, resp_err;
614     struct domain_entry *entry;
615     err = domain_get_by_cap(domain_cap, &entry);
616     if (err_is_fail(err)) {
617         goto respond;
618     }
619
620     if (entry->status == DOMAIN_STATUS_STOPPED) {
621         // Domain has already been stopped, so just reply with exit status.
622         goto respond;
623     }
624
625     struct domain_waiter *waiter = (struct domain_waiter*) malloc(
626             sizeof(struct domain_waiter));
627     waiter->b = b;
628     waiter->next = entry->waiters;
629     entry->waiters = waiter;
630     // Will respond when domain is stopped.
631     return;
632
633 respond:
634     resp_err = b->tx_vtbl.wait_response(b, NOP_CONT, err, entry->exit_status);
635     if (err_is_fail(resp_err)) {
636         DEBUG_ERR(resp_err, "failed to send wait_response");
637     }
638 }
639
640 static struct proc_mgmt_rx_vtbl monitor_vtbl = {
641     .add_spawnd           = add_spawnd_handler,
642     .spawn_call           = spawn_handler,
643     .spawn_with_caps_call = spawn_with_caps_handler,
644     .span_call            = span_handler,
645     .kill_call            = kill_handler,
646     .exit_call            = exit_handler,
647     .wait_call            = wait_handler
648 };
649
650 static struct proc_mgmt_rx_vtbl non_monitor_vtbl = {
651     .add_spawnd           = add_spawnd_handler_non_monitor,
652     .spawn_call           = spawn_handler,
653     .spawn_with_caps_call = spawn_with_caps_handler,
654     .span_call            = span_handler,
655     .kill_call            = kill_handler,
656     .exit_call            = exit_handler,
657     .wait_call            = wait_handler
658 };
659
660 /**
661  * \brief Allocates a special LMP endpoint for authenticating with the monitor.
662  */
663 static errval_t alloc_ep_for_monitor(struct capref *ep)
664 {
665     struct proc_mgmt_lmp_binding *lmpb =
666         malloc(sizeof(struct proc_mgmt_lmp_binding));
667     assert(lmpb != NULL);
668
669     // setup our end of the binding
670     errval_t err = proc_mgmt_client_lmp_accept(lmpb, get_default_waitset(),
671                                                DEFAULT_LMP_BUF_WORDS);
672     if (err_is_fail(err)) {
673         free(lmpb);
674         return err_push(err, LIB_ERR_PROC_MGMT_CLIENT_ACCEPT);
675     }
676
677     *ep = lmpb->chan.local_cap;
678     lmpb->b.rx_vtbl = monitor_vtbl;
679
680     return SYS_ERR_OK;
681 }
682
683 static void export_cb(void *st, errval_t err, iref_t iref)
684 {
685     if (err_is_fail(err)) {
686         USER_PANIC_ERR(err, "export failed");
687     }
688
689     // Allocate an endpoint for the local monitor, who will use it to inform
690     // us about new spawnd irefs on behalf of other monitors.
691     struct capref ep;
692     err = alloc_ep_for_monitor(&ep);
693     if (err_is_fail(err)) {
694         USER_PANIC_ERR(err, "failed to allocate LMP EP for local monitor");
695     }
696
697     // Send the endpoint to the monitor, so it can finish the handshake.
698     struct monitor_binding *mb = get_monitor_binding();
699     err = mb->tx_vtbl.set_proc_mgmt_ep_request(mb, NOP_CONT, ep);
700     if (err_is_fail(err)) {
701         USER_PANIC_ERR(err, "failed to send set_proc_mgmt_ep_request to "
702                        "monitor");
703     }
704
705     // Also register this iref with the name service, for arbitrary client
706     // domains to use for spawn-related ops.
707     err = nameservice_register(SERVICE_BASENAME, iref);
708     if (err_is_fail(err)) {
709         USER_PANIC_ERR(err, "nameservice_register failed");
710     }
711 }
712
713 static errval_t connect_cb(void *st, struct proc_mgmt_binding *b)
714 {
715     b->rx_vtbl = non_monitor_vtbl;
716     return SYS_ERR_OK;
717 }
718
719 errval_t start_service(void)
720 {
721     errval_t err = domain_prealloc_caps();
722     if (err_is_fail(err)) {
723         USER_PANIC_ERR(err_push(err, PROC_MGMT_ERR_CREATE_DOMAIN_CAP),
724                        "domain_prealloc_caps in start_service");
725     }
726
727     return proc_mgmt_export(NULL, export_cb, connect_cb, get_default_waitset(),
728             IDC_EXPORT_FLAGS_DEFAULT);
729 }