First outline of a process management service server.
[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/proc_mgmt_client.h>
17 #include <if/proc_mgmt_defs.h>
18
19 static void error_handler(struct proc_mgmt_binding *b, errval_t err)
20 {
21 #if defined(__x86_64__) || defined(__i386__)
22     debug_printf("%p %p %p %p\n", __builtin_return_address(0), __builtin_return_address(1),__builtin_return_address(2),__builtin_return_address(3));
23 #endif
24     debug_err(__FILE__, __func__, __LINE__, err,
25               "error in proc_mgmt binding");
26     abort();
27 }
28
29 static void proc_mgmt_accept_recv_handler(void *arg)
30 {
31     struct proc_mgmt_lmp_binding *b = arg;
32     struct lmp_recv_msg msg = LMP_RECV_MSG_INIT;
33     struct capref cap;
34     errval_t err;
35
36     // try to retrieve a message from the channel
37     err = lmp_chan_recv(&b->chan, &msg, &cap);
38     if (err_is_fail(err)) {
39         if (err_no(err) == LIB_ERR_NO_LMP_MSG) {
40             // nothing there, re-register
41             struct event_closure recv_handler = {
42                 .handler = proc_mgmt_accept_recv_handler,
43                 .arg = b,
44             };
45             err = lmp_chan_register_recv(&b->chan, b->b.waitset, recv_handler);
46             b->b.error_handler(&b->b,
47                     err_push(err, LIB_ERR_CHAN_REGISTER_RECV));
48         } else {
49             // real error, report to user
50             b->b.error_handler(&b->b, err_push(err, LIB_ERR_LMP_CHAN_RECV));
51         }
52         return;
53     }
54
55     // if we're the monitor, we might be waiting for the other side's cap
56     // TODO(razvan): Or the process manager, which for uses LMP_MONITOR_ACCEPT
57     // as well.
58     assert(b->chan.connstate == LMP_MONITOR_ACCEPT);
59     assert(!capref_is_null(cap));
60     b->chan.remote_cap = cap;
61     b->chan.connstate = LMP_CONNECTED;
62
63     // Allocate a new receive slot.
64     // TODO(razvan): Whom is the receive slot for? Is it one of the spawnds?
65     // Or is it some arbitrary non-spawnd client domain? Need a way to tell.
66     err = lmp_chan_alloc_recv_slot(&b->chan);
67     if (err_is_fail(err)) {
68         // XXX: report the error, but continue
69         b->b.error_handler(&b->b, err_push(err, LIB_ERR_LMP_ALLOC_RECV_SLOT));
70     }
71
72     // Run the RX handler; has a side-effect of registering for receive events.
73     proc_mgmt_lmp_rx_handler(b);
74 }
75
76 static errval_t init_lmp_binding(struct proc_mgmt_lmp_binding *lmpb,
77                                  struct waitset *ws, size_t buflen_words)
78 {
79     errval_t err;
80
81     proc_mgmt_lmp_init(lmpb, ws);
82
83     /* allocate a cap slot for the new endpoint cap */
84     err = slot_alloc(&lmpb->chan.local_cap);
85     if (err_is_fail(err)) {
86         return err_push(err, LIB_ERR_SLOT_ALLOC);
87     }
88
89     /* allocate a local endpoint */
90     err = lmp_endpoint_create_in_slot(buflen_words, lmpb->chan.local_cap,
91             &lmpb->chan.endpoint);
92     if (err_is_fail(err)) {
93         /* TODO: free cap slot */
94         return err_push(err, LIB_ERR_ENDPOINT_CREATE);
95     }
96
97     /* allocate an initial receive slot */
98     err = lmp_chan_alloc_recv_slot(&lmpb->chan);
99     if (err_is_fail(err)) {
100         return err;
101     }
102
103     /* setup error handler */
104     lmpb->b.error_handler = error_handler;
105
106     /* setup initial receive handlers */
107     // lmpb->b.rx_vtbl = proc_mgmt_rx_vtbl;
108
109     // connect handlers
110     lmpb->b.change_waitset(&lmpb->b, lmpb->b.waitset);
111     return SYS_ERR_OK;
112 }
113
114 /**
115  * \brief Accept a new LMP binding in a client from the process manager.
116  *
117  * Should only be used in the process manager.
118  *
119  * \param pmcb         Storage for binding state
120  * \param ws           Waitset for handling incoming messages
121  * \param buflen_words Size of incoming buffer, in number of words
122  */
123 errval_t proc_mgmt_client_lmp_accept(struct proc_mgmt_lmp_binding *lmpb,
124         struct waitset *ws, size_t lmp_buflen_words)
125 {
126     errval_t err = init_lmp_binding(lmpb, ws, lmp_buflen_words);
127     if (err_is_fail(err)) {
128         return err;
129     }
130
131     // TODO(razvan): This should probably be something like LMP_PROC_MGMT_ACCEPT
132     lmpb->chan.connstate = LMP_MONITOR_ACCEPT;
133     lmpb->chan.remote_cap = NULL_CAP; // will be sent to us by the client
134
135     // Register for receive notification on our special handler.
136     struct event_closure receive_handler = {
137         .handler = proc_mgmt_accept_recv_handler,
138         .arg = lmpb,
139     };
140     err = lmp_chan_register_recv(&lmpb->chan, ws, receive_handler);
141     if (err_is_fail(err)) {
142         return err; // TODO: cleanup?
143     }
144
145     return SYS_ERR_OK;
146 }