Create "ProcessManager" and "Domain" capabilities.
[barrelfish] / lib / barrelfish / proc_mgmt_client.c
1 /**
2  * \file
3  * \brief Client for interacting with the process management server.
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 <if/octopus_defs.h>
19 #include <if/proc_mgmt_defs.h>
20
21 struct proc_mgmt_bind_retst {
22     errval_t err;
23     struct proc_mgmt_binding *b;
24     bool present;
25 };
26
27 static void error_handler(struct proc_mgmt_binding *b, errval_t err)
28 {
29 #if defined(__x86_64__) || defined(__i386__)
30     debug_printf("%p %p %p %p\n",
31                  __builtin_return_address(0),
32                  __builtin_return_address(1),
33                  __builtin_return_address(2),
34                  __builtin_return_address(3));
35 #endif
36     debug_err(__FILE__, __func__, __LINE__, err,
37               "asynchronous error in proc_mgmt binding");
38     abort();
39 }
40
41 static void proc_mgmt_bind_cont(void *st, errval_t err,
42         struct proc_mgmt_binding *b)
43 {
44     struct proc_mgmt_bind_retst *retst = (struct proc_mgmt_bind_retst*) st;
45     assert(retst != NULL);
46     assert(!retst->present);
47     retst->err = err;
48     retst->b = b;
49     retst->present = true;
50 }
51
52 static void proc_mgmt_accept_recv_handler(void *arg)
53 {
54     struct proc_mgmt_lmp_binding *b = arg;
55     struct lmp_recv_msg msg = LMP_RECV_MSG_INIT;
56     struct capref cap;
57     errval_t err;
58
59     // try to retrieve a message from the channel
60     err = lmp_chan_recv(&b->chan, &msg, &cap);
61     if (err_is_fail(err)) {
62         if (err_no(err) == LIB_ERR_NO_LMP_MSG) {
63             // nothing there, re-register
64             struct event_closure recv_handler = {
65                 .handler = proc_mgmt_accept_recv_handler,
66                 .arg = b,
67             };
68             err = lmp_chan_register_recv(&b->chan, b->b.waitset, recv_handler);
69             b->b.error_handler(&b->b, err_push(err, LIB_ERR_CHAN_REGISTER_RECV));
70         } else {
71             // real error, report to user
72             b->b.error_handler(&b->b, err_push(err, LIB_ERR_LMP_CHAN_RECV));
73         }
74         return;
75     }
76
77     // TODO(razvan): LMP_PROC_MGMT_ACCEPT ?
78     assert(b->chan.connstate == LMP_MONITOR_ACCEPT);
79     assert(!capref_is_null(cap));
80     b->chan.remote_cap = cap;
81     b->chan.connstate = LMP_CONNECTED;
82
83     /* allocate a new receive slot */
84     err = lmp_chan_alloc_recv_slot(&b->chan);
85     if (err_is_fail(err)) {
86         // XXX: report the error, but continue
87         b->b.error_handler(&b->b, err_push(err, LIB_ERR_LMP_ALLOC_RECV_SLOT));
88     }
89
90     /* Run the RX handler; has a side-effect of registering for receive events */
91     proc_mgmt_lmp_rx_handler(b);
92 }
93
94 static errval_t init_lmp_binding(struct proc_mgmt_lmp_binding *lmpb,
95                                  struct waitset *ws,
96                                  size_t buflen_words)
97 {
98     errval_t err;
99
100     proc_mgmt_lmp_init(lmpb, ws);
101
102     /* allocate a cap slot for the new endpoint cap */
103     err = slot_alloc(&lmpb->chan.local_cap);
104     if (err_is_fail(err)) {
105         return err_push(err, LIB_ERR_SLOT_ALLOC);
106     }
107
108     /* allocate a local endpoint */
109     err = lmp_endpoint_create_in_slot(buflen_words, lmpb->chan.local_cap,
110                                       &lmpb->chan.endpoint);
111     if (err_is_fail(err)) {
112         // TODO(razvan): Free cap slot.
113         return err_push(err, LIB_ERR_ENDPOINT_CREATE);
114     }
115
116     /* allocate an initial receive slot */
117     err = lmp_chan_alloc_recv_slot(&lmpb->chan);
118     if (err_is_fail(err)) {
119         return err;
120     }
121
122     /* setup error handler */
123     lmpb->b.error_handler = error_handler;
124
125     /* setup initial receive handlers */
126     // TODO(razvan): Don't think this is needed, but dunno for sure yet.
127     // lmpb->b.rx_vtbl = monitor_rx_vtbl;
128
129     // connect handlers
130     lmpb->b.change_waitset(&lmpb->b, lmpb->b.waitset);
131     return SYS_ERR_OK;
132 }
133
134 /**
135  * \brief Accept a new LMP binding to a proc mgmt client.
136  *
137  * Should only be used in the process manager.
138  *
139  * \param lmpb         Storage for binding state
140  * \param ws           Waitset for handling incoming messages
141  * \param buflen_words Size of incoming buffer, in number of words
142  */
143 errval_t proc_mgmt_client_lmp_accept(struct proc_mgmt_lmp_binding *lmpb,
144                                      struct waitset *ws,
145                                      size_t lmp_buflen_words)
146 {
147     errval_t err = init_lmp_binding(lmpb, ws, lmp_buflen_words);
148     if (err_is_fail(err)) {
149         return err;
150     }
151
152     lmpb->chan.connstate = LMP_MONITOR_ACCEPT;  // TODO(razvan): LMP_PROC_MGMT_ACCEPT?
153     lmpb->chan.remote_cap = NULL_CAP; // will be sent to us by the client
154
155     /* Register for receive notification on our special handler */
156     struct event_closure receive_handler = {
157         .handler = proc_mgmt_accept_recv_handler,
158         .arg = lmpb,
159     };
160     err = lmp_chan_register_recv(&lmpb->chan, ws, receive_handler);
161     if (err_is_fail(err)) {
162         return err;  // TODO(razvan): cleanup?
163     }
164
165     return SYS_ERR_OK;
166 }
167
168
169 /**
170  * \brief Initiate a new LMP binding to the process manager
171  *
172  * To be used by the monitor for setting up the privileged channel used for
173  * spawnd discovery.
174  * Requires an explicit remote endpoint cap allocated by the process manager.
175  *
176  * \param lmpb         Storage for binding state
177  * \param ep           Remote endpoint of the process manager
178  * \param ws           Waitset for handling incoming messages
179  * \param cont         Continuation for when binding completes or fails
180  * \param st           State passed to continuation function
181  * \param buflen_words Size of incoming buffer, in number of words
182  */
183 errval_t proc_mgmt_client_lmp_bind(struct proc_mgmt_lmp_binding *lmpb,
184                                    struct capref ep,
185                                    proc_mgmt_bind_continuation_fn *cont,
186                                    void *st,
187                                    struct waitset *ws,
188                                    size_t lmp_buflen_words)
189 {
190     errval_t err = init_lmp_binding(lmpb, ws, lmp_buflen_words);
191     if (err_is_fail(err)) {
192         return err;
193     }
194
195     lmpb->chan.remote_cap = ep;
196
197     // Send the local endpoint cap to the process manager.
198     lmpb->chan.connstate = LMP_CONNECTED; /* pre-established */
199     err = lmp_chan_send0(&lmpb->chan, 0, lmpb->chan.local_cap);
200     if (err_is_fail(err)) {
201         // TODO(razvan): This, below.
202         /* XXX: I'm lazily assuming this can never fail with a transient error,
203          * since we only do it once at dispatcher startup. If not, we need to
204          * register and retry here */
205         assert(!lmp_err_is_transient(err));
206         return err;
207     }
208
209     /* Run the RX handler; has a side-effect of registering for receive events */
210     proc_mgmt_lmp_rx_handler(lmpb);
211
212     /* Run the continuation */
213     cont(st, SYS_ERR_OK, &lmpb->b);
214
215     return SYS_ERR_OK;
216 }
217
218 errval_t proc_mgmt_bind_client(void)
219 {
220     struct proc_mgmt_binding *b = get_proc_mgmt_binding();
221     if (b != NULL) {
222         return SYS_ERR_OK;
223     }
224
225     errval_t err;
226     iref_t iref;
227     // Try using nameserver to retrievew the proc mgmt iref.
228     err = nameservice_blocking_lookup("proc_mgmt", &iref);
229     if (err_is_fail(err)) {
230         return err;
231     }
232     
233     // Initiate bind.
234     struct proc_mgmt_bind_retst bindst = {
235         .present = false
236     };
237
238     err = proc_mgmt_bind(iref, proc_mgmt_bind_cont, &bindst,
239             get_default_waitset(), /*IDC_BIND_FLAG_RPC_CAP_TRANSFER*/IDC_BIND_FLAGS_DEFAULT);
240     if (err_is_fail(err)) {
241         USER_PANIC_ERR(err, "proc_mgmt_bind");
242     }
243
244     // Wait for bind completion.
245     while (!bindst.present) {
246         messages_wait_and_handle_next();
247     }
248
249     if (err_is_fail(bindst.err)) {
250         return bindst.err;
251     }
252
253     proc_mgmt_rpc_client_init(bindst.b);
254
255     set_proc_mgmt_binding(bindst.b);
256
257     return SYS_ERR_OK;
258 }
259
260 errval_t proc_mgmt_add_spawnd(iref_t iref, coreid_t core_id)
261 {
262     errval_t err = proc_mgmt_bind_client();
263     if (err_is_fail(err)) {
264         DEBUG_ERR(err, "proc_mgmt_bind_client");
265         return err;
266     }
267
268     struct proc_mgmt_binding *b = get_proc_mgmt_binding();
269     assert(b != NULL);
270
271     err = b->tx_vtbl.add_spawnd(b, NOP_CONT, core_id, iref);
272     if (err_is_fail(err)) {
273         DEBUG_ERR(err, "add_spawnd");
274     }
275
276     return err;
277 }