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