3 * \brief Client for interacting with the process management server.
7 * Copyright (c) 2017, 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/nameservice_client.h>
17 #include <barrelfish/proc_mgmt_client.h>
18 #include <if/octopus_defs.h>
19 #include <if/proc_mgmt_defs.h>
21 struct proc_mgmt_bind_retst {
23 struct proc_mgmt_binding *b;
27 static void error_handler(struct proc_mgmt_binding *b, errval_t err)
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));
36 debug_err(__FILE__, __func__, __LINE__, err,
37 "asynchronous error in proc_mgmt binding");
41 static void proc_mgmt_bind_cont(void *st, errval_t err,
42 struct proc_mgmt_binding *b)
44 struct proc_mgmt_bind_retst *retst = (struct proc_mgmt_bind_retst*) st;
45 assert(retst != NULL);
46 assert(!retst->present);
49 retst->present = true;
52 static void proc_mgmt_accept_recv_handler(void *arg)
54 struct proc_mgmt_lmp_binding *b = arg;
55 struct lmp_recv_msg msg = LMP_RECV_MSG_INIT;
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,
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));
71 // real error, report to user
72 b->b.error_handler(&b->b, err_push(err, LIB_ERR_LMP_CHAN_RECV));
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;
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));
90 /* Run the RX handler; has a side-effect of registering for receive events */
91 proc_mgmt_lmp_rx_handler(b);
94 static errval_t init_lmp_binding(struct proc_mgmt_lmp_binding *lmpb,
100 proc_mgmt_lmp_init(lmpb, ws);
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);
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);
116 /* allocate an initial receive slot */
117 err = lmp_chan_alloc_recv_slot(&lmpb->chan);
118 if (err_is_fail(err)) {
122 /* setup error handler */
123 lmpb->b.error_handler = error_handler;
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;
130 lmpb->b.change_waitset(&lmpb->b, lmpb->b.waitset);
135 * \brief Accept a new LMP binding to a proc mgmt client.
137 * Should only be used in the process manager.
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
143 errval_t proc_mgmt_client_lmp_accept(struct proc_mgmt_lmp_binding *lmpb,
145 size_t lmp_buflen_words)
147 errval_t err = init_lmp_binding(lmpb, ws, lmp_buflen_words);
148 if (err_is_fail(err)) {
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
155 /* Register for receive notification on our special handler */
156 struct event_closure receive_handler = {
157 .handler = proc_mgmt_accept_recv_handler,
160 err = lmp_chan_register_recv(&lmpb->chan, ws, receive_handler);
161 if (err_is_fail(err)) {
162 return err; // TODO(razvan): cleanup?
170 * \brief Initiate a new LMP binding to the process manager
172 * To be used by the monitor for setting up the privileged channel used for
174 * Requires an explicit remote endpoint cap allocated by the process manager.
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
183 errval_t proc_mgmt_client_lmp_bind(struct proc_mgmt_lmp_binding *lmpb,
185 proc_mgmt_bind_continuation_fn *cont,
188 size_t lmp_buflen_words)
190 errval_t err = init_lmp_binding(lmpb, ws, lmp_buflen_words);
191 if (err_is_fail(err)) {
195 lmpb->chan.remote_cap = ep;
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));
209 /* Run the RX handler; has a side-effect of registering for receive events */
210 proc_mgmt_lmp_rx_handler(lmpb);
212 /* Run the continuation */
213 cont(st, SYS_ERR_OK, &lmpb->b);
218 errval_t proc_mgmt_bind_client(void)
220 struct proc_mgmt_binding *b = get_proc_mgmt_binding();
227 // Try using nameserver to retrievew the proc mgmt iref.
228 err = nameservice_blocking_lookup("proc_mgmt", &iref);
229 if (err_is_fail(err)) {
234 struct proc_mgmt_bind_retst bindst = {
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");
244 // Wait for bind completion.
245 while (!bindst.present) {
246 messages_wait_and_handle_next();
249 if (err_is_fail(bindst.err)) {
253 proc_mgmt_rpc_client_init(bindst.b);
255 set_proc_mgmt_binding(bindst.b);
260 errval_t proc_mgmt_add_spawnd(iref_t iref, coreid_t core_id)
262 errval_t err = proc_mgmt_bind_client();
263 if (err_is_fail(err)) {
264 DEBUG_ERR(err, "proc_mgmt_bind_client");
268 struct proc_mgmt_binding *b = get_proc_mgmt_binding();
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");