3 * \brief Client for interacting with the monitor
7 * Copyright (c) 2010, 2011, 2012, ETH Zurich.
10 * This file is distributed under the terms in the attached LICENSE file.
11 * If you do not find this file, copies can be found by writing to:
12 * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
15 #include <barrelfish/barrelfish.h>
16 #include <barrelfish/dispatcher_arch.h>
17 #include <if/monitor_defs.h>
18 #include <barrelfish/monitor_client.h>
19 #include <if/monitor_blocking_rpcclient_defs.h>
23 static void error_handler(struct monitor_binding *b, errval_t err)
25 #if defined(__x86_64__) || defined(__i386__)
26 debug_printf("%p %p %p %p\n", __builtin_return_address(0), __builtin_return_address(1),__builtin_return_address(2),__builtin_return_address(3));
28 debug_err(__FILE__, __func__, __LINE__, err,
29 "asynchronous error in monitor binding");
33 /// Handler for incoming LMP messages from the monitor binding with an
34 /// indirected cap for a UMP/BMP/... channel
35 static void cap_receive_request_handler(struct monitor_binding *b,
36 uintptr_t conn_id, errval_t success,
37 struct capref cap, uint32_t capid)
39 /* XXX: this relies on the monitor_cap_handlers table being the first thing
40 * in every channel state struct */
41 struct monitor_cap_handlers *h = (void *)conn_id;
42 assert(h->cap_receive_handler != NULL);
43 h->cap_receive_handler(h->st, success, cap, capid);
46 /// vtable for handlers declared in this file
47 // other handlers are set directly on the binding by various init()
48 // functions after we bind to the monitor
49 static struct monitor_rx_vtbl monitor_rx_vtbl = {
50 .cap_receive_request = cap_receive_request_handler,
53 static void monitor_accept_recv_handler(void *arg)
55 struct monitor_lmp_binding *b = arg;
56 struct lmp_recv_msg msg = LMP_RECV_MSG_INIT;
60 // try to retrieve a message from the channel
61 err = lmp_chan_recv(&b->chan, &msg, &cap);
62 if (err_is_fail(err)) {
63 if (err_no(err) == LIB_ERR_NO_LMP_MSG) {
64 // nothing there, re-register
65 struct event_closure recv_handler = {
66 .handler = monitor_accept_recv_handler,
69 err = lmp_chan_register_recv(&b->chan, b->b.waitset, recv_handler);
70 b->b.error_handler(&b->b, err_push(err, LIB_ERR_CHAN_REGISTER_RECV));
72 // real error, report to user
73 b->b.error_handler(&b->b, err_push(err, LIB_ERR_LMP_CHAN_RECV));
78 // if we're the monitor, we might be waiting for the other side's cap
79 assert(b->chan.connstate == LMP_MONITOR_ACCEPT);
80 assert(!capref_is_null(cap));
81 b->chan.remote_cap = cap;
82 b->chan.connstate = LMP_CONNECTED;
84 /* allocate a new receive slot */
85 err = lmp_chan_alloc_recv_slot(&b->chan);
86 if (err_is_fail(err)) {
87 // XXX: report the error, but continue
88 b->b.error_handler(&b->b, err_push(err, LIB_ERR_LMP_ALLOC_RECV_SLOT));
91 /* Run the RX handler; has a side-effect of registering for receive events */
92 monitor_lmp_rx_handler(b);
95 static errval_t init_lmp_binding(struct monitor_lmp_binding *mcb,
96 struct waitset *ws, size_t buflen_words)
100 monitor_lmp_init(mcb, ws);
102 /* allocate a cap slot for the new endpoint cap */
103 err = slot_alloc(&mcb->chan.local_cap);
104 if (err_is_fail(err)) {
105 return err_push(err, LIB_ERR_SLOT_ALLOC);
108 /* allocate a local endpoint */
109 err = lmp_endpoint_create_in_slot(buflen_words, mcb->chan.local_cap,
110 &mcb->chan.endpoint);
111 if (err_is_fail(err)) {
112 /* TODO: free cap slot */
113 return err_push(err, LIB_ERR_ENDPOINT_CREATE);
116 /* allocate an initial receive slot */
117 err = lmp_chan_alloc_recv_slot(&mcb->chan);
118 if (err_is_fail(err)) {
122 /* setup error handler */
123 mcb->b.error_handler = error_handler;
125 /* setup initial receive handlers */
126 mcb->b.rx_vtbl = monitor_rx_vtbl;
132 * \brief Initiate a new LMP binding to the monitor
134 * Must only be called once at startup time on any dispatcher.
136 * \param mcb Storage for binding state
137 * \param ws Waitset for handling incoming messages
138 * \param cont Continuation for when binding completes or fails
139 * \param st State passed to continuation function
140 * \param buflen_words Size of incoming buffer, in number of words
142 errval_t monitor_client_lmp_bind(struct monitor_lmp_binding *mcb,
143 monitor_bind_continuation_fn *cont, void *st,
144 struct waitset *ws, size_t lmp_buflen_words)
146 errval_t err = init_lmp_binding(mcb, ws, lmp_buflen_words);
147 if (err_is_fail(err)) {
151 mcb->chan.remote_cap = cap_monitorep;
153 /* Send the local endpoint cap to the monitor */
154 mcb->chan.connstate = LMP_CONNECTED; /* pre-established */
155 err = lmp_chan_send0(&mcb->chan, 0, mcb->chan.local_cap);
156 if (err_is_fail(err)) {
157 /* XXX: I'm lazily assuming this can never fail with a transient error,
158 * since we only do it once at dispatcher startup. If not, we need to
159 * register and retry here */
160 assert(!lmp_err_is_transient(err));
164 /* Run the RX handler; has a side-effect of registering for receive events */
165 monitor_lmp_rx_handler(mcb);
167 /* Run the continuation */
168 cont(st, SYS_ERR_OK, &mcb->b);
174 * \brief Accept a new LMP binding in a client from the monitor
176 * Should only be used in the monitor.
178 * \param mcb Storage for binding state
179 * \param ws Waitset for handling incoming messages
180 * \param buflen_words Size of incoming buffer, in number of words
182 errval_t monitor_client_lmp_accept(struct monitor_lmp_binding *mcb,
183 struct waitset *ws, size_t lmp_buflen_words)
185 errval_t err = init_lmp_binding(mcb, ws, lmp_buflen_words);
186 if (err_is_fail(err)) {
190 mcb->chan.connstate = LMP_MONITOR_ACCEPT;
191 mcb->chan.remote_cap = NULL_CAP; // will be sent to us by the client
193 /* Register for receive notification on our special handler */
194 struct event_closure receive_handler = {
195 .handler = monitor_accept_recv_handler,
198 err = lmp_chan_register_recv(&mcb->chan, ws, receive_handler);
199 if (err_is_fail(err)) {
200 return err; // TODO: cleanup?
206 static void new_monitor_binding_reply_handler(struct monitor_binding *b,
207 errval_t err, struct capref ep,
210 struct monitor_lmp_binding *lmpb = (void *)st;
212 if (err_is_fail(err)) {
216 // success! store the cap
217 lmpb->chan.remote_cap = ep;
219 /* Send the local endpoint cap to the monitor */
220 lmpb->chan.connstate = LMP_CONNECTED; /* pre-established */
221 err = lmp_chan_send0(&lmpb->chan, 0, lmpb->chan.local_cap);
222 if (err_is_fail(err) && lmp_err_is_transient(err)) {
223 // XXX: TODO: stack-rip, register send event and retry!
224 USER_PANIC_ERR(err, "AB was lazy and didn't bother to retry a transient send error");
228 /* Run the continuation */
229 assert(lmpb->b.bind_cont != NULL);
230 lmpb->b.bind_cont(lmpb->b.st, err, &lmpb->b);
232 if (err_is_fail(err)) {
233 // destroy the binding
234 monitor_lmp_destroy(lmpb);
239 static void new_monitor_binding_request_sender(void *arg)
241 struct monitor_lmp_binding *lmpb = arg; // new binding
242 struct monitor_binding *mb = get_monitor_binding();
245 /* Send request to the monitor on our existing binding */
246 err = mb->tx_vtbl.new_monitor_binding_request(mb, NOP_CONT, (uintptr_t)lmpb);
247 if (err_is_ok(err)) {
248 event_mutex_unlock(&mb->mutex);
249 } else if (err_no(err) == FLOUNDER_ERR_TX_BUSY) {
250 err = mb->register_send(mb, mb->waitset,
251 MKCONT(new_monitor_binding_request_sender,lmpb));
252 assert(err_is_ok(err)); // shouldn't fail, as we have the mutex
253 } else { // permanent error
254 event_mutex_unlock(&mb->mutex);
255 lmpb->b.bind_cont(lmpb->b.st, err, &lmpb->b);
256 monitor_lmp_destroy(lmpb);
262 * \brief Initiate a new (subsequent to boot) LMP binding to the monitor
264 * May be called after initialisation to create another binding to the monitor.
265 * Must not be called in the monitor.
267 * \param cont Continuation for when binding completes or fails
268 * \param st State passed to continuation function
269 * \param buflen_words Size of incoming buffer, in number of words
270 * \param ws Waitset for handling incoming messages
272 errval_t monitor_client_new_binding(monitor_bind_continuation_fn *cont, void *st,
273 struct waitset *ws, size_t lmp_buflen_words)
277 // allocate space for the binding state
278 struct monitor_lmp_binding *lmpb = malloc(sizeof(struct monitor_lmp_binding));
280 return LIB_ERR_MALLOC_FAIL;
283 err = init_lmp_binding(lmpb, ws, lmp_buflen_words);
284 if (err_is_fail(err)) {
289 // copy the rx_vtbl from the main monitor binding
290 struct monitor_binding *mcb = get_monitor_binding();
291 lmpb->b.rx_vtbl = mcb->rx_vtbl;
293 // store continuation
294 lmpb->b.bind_cont = cont;
297 /* Run the RX handler; has a side-effect of registering for receive events */
298 monitor_lmp_rx_handler(lmpb);
300 /* Set reply handler (should only need to do this once!) */
301 mcb->rx_vtbl.new_monitor_binding_reply = new_monitor_binding_reply_handler;
303 /* Wait to use the monitor binding */
304 event_mutex_enqueue_lock(&mcb->mutex, &lmpb->b.event_qnode,
305 MKCLOSURE(new_monitor_binding_request_sender,lmpb));
310 errval_t monitor_cap_set_remote(struct capref cap, bool remote)
314 struct monitor_blocking_rpc_client *mc = get_monitor_blocking_rpc_client();
316 errval_t err, reterr;
318 err = mc->vtbl.cap_set_remote(mc, cap, remote, &reterr);
319 if(err_is_fail(err)) {
332 static void monitor_rpc_bind_continuation(void *st_arg, errval_t err,
333 struct monitor_blocking_binding *b)
335 struct bind_state *st = st_arg;
337 if (err_is_ok(err)) {
338 struct monitor_blocking_rpc_client *r =
339 malloc(sizeof(struct monitor_blocking_rpc_client));
341 err = monitor_blocking_rpc_client_init(r, b);
342 if (err_is_fail(err)) {
344 USER_PANIC_ERR(err, "error in mem_rpc_client_init");
346 set_monitor_blocking_rpc_client(r);
354 static void get_monitor_rpc_iref_reply(struct monitor_binding *mb, iref_t iref,
359 struct bind_state *st = (void *)st_arg;
361 st->err = LIB_ERR_GET_MON_BLOCKING_IREF;
366 struct monitor_blocking_lmp_binding *mbb = malloc(sizeof(*mbb));
369 err = monitor_blocking_lmp_bind(mbb, iref, monitor_rpc_bind_continuation,
370 st, get_default_waitset(),
371 IDC_BIND_FLAG_RPC_CAP_TRANSFER,
373 if (err_is_fail(err)) {
380 * \brief Sets up binding to monitor's blocking rpc channel
382 errval_t monitor_client_blocking_rpc_init(void)
386 struct bind_state st = { .done = false };
388 /* fire off a request for the iref for monitor rpc channel */
389 struct monitor_binding *mb = get_monitor_binding();
390 mb->rx_vtbl.get_monitor_rpc_iref_reply = get_monitor_rpc_iref_reply;
391 err = mb->tx_vtbl.get_monitor_rpc_iref_request(mb, NOP_CONT,
393 if (err_is_fail(err)) {
394 return err_push(err, LIB_ERR_GET_MON_BLOCKING_IREF);
398 /* block on the default waitset until we're bound */
399 struct waitset *ws = get_default_waitset();
401 err = event_dispatch(ws);
402 if (err_is_fail(err)) {
403 return err_push(err, LIB_ERR_EVENT_DISPATCH);
410 errval_t monitor_debug_print_cababilities(void)
414 struct monitor_binding *mb = get_monitor_binding();
415 err = mb->tx_vtbl.debug_print_capabilities(mb, NOP_CONT);