55c90b9e9c6f35e7a7ab1a3be99e4a4f5faaaa34
[akaros.git] / user / parlib / event.c
1 /* Copyright (c) 2011 The Regents of the University of California
2  * Barret Rhoden <brho@cs.berkeley.edu>
3  * See LICENSE for details.
4  *
5  * Userspace utility functions for receiving events and notifications (IPIs).
6  * Some are higher level than others; just use what you need. */ 
7
8 #include <ros/event.h>
9 #include <ros/procdata.h>
10 #include <ucq.h>
11 #include <bitmask.h>
12 #include <vcore.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <assert.h>
16 #include <errno.h>
17 #include <parlib.h>
18 #include <event.h>
19 #include <uthread.h>
20
21 /********* Event_q Setup / Registration  ***********/
22
23 /* Get event_qs via these interfaces, since eventually we'll want to either
24  * allocate from pinned memory or use some form of a slab allocator.  Also,
25  * these stitch up the big_q so its ev_mbox points to its internal mbox.  Never
26  * access the internal mbox directly.
27  *
28  * Raw ones need to have their UCQs initialized.  If you're making a lot of
29  * these, you can do one big mmap and init the ucqs on your own, which ought to
30  * perform better.
31  *
32  * Use the 'regular' one for big_qs if you don't want to worry about the ucq
33  * initalization */
34 struct event_queue *get_big_event_q_raw(void)
35 {
36         /* TODO: (PIN) should be pinned memory */
37         struct event_queue_big *big_q = malloc(sizeof(struct event_queue_big));
38         memset(big_q, 0, sizeof(struct event_queue_big));
39         big_q->ev_mbox = &big_q->ev_imbox;
40         return (struct event_queue*)big_q;
41 }
42
43 struct event_queue *get_big_event_q(void)
44 {
45         struct event_queue *big_q = get_big_event_q_raw();
46         /* uses the simpler, internally mmapping ucq_init() */
47         ucq_init(&big_q->ev_mbox->ev_msgs);
48         return big_q;
49 }
50
51 /* Give it up.  I don't recommend calling these unless you're sure the queues
52  * aren't in use (unregistered, etc). (TODO: consider some checks for this) */
53 void put_big_event_q_raw(struct event_queue *ev_q)
54 {
55         /* if we use something other than malloc, we'll need to be aware that ev_q
56          * is actually an event_queue_big.  One option is to use the flags, though
57          * this could be error prone. */
58         free(ev_q);
59 }
60
61 void put_big_event_q(struct event_queue *ev_q)
62 {
63         ucq_free_pgs(&ev_q->ev_mbox->ev_msgs);
64         put_big_event_q_raw(ev_q);
65 }
66
67 /* Need to point this event_q to an mbox - usually to a vcpd */
68 struct event_queue *get_event_q(void)
69 {
70         /* TODO: (PIN) should be pinned memory */
71         struct event_queue *ev_q = malloc(sizeof(struct event_queue));
72         memset(ev_q, 0, sizeof(struct event_queue));
73         return ev_q;
74 }
75
76 /* Gets a small ev_q, with ev_mbox pointing to the vcpd mbox of vcoreid.  If
77  * ev_flags has EVENT_VCORE_PRIVATE set, it'll give you the private mbox.  o/w,
78  * you'll get the public one. */
79 struct event_queue *get_event_q_vcpd(uint32_t vcoreid, int ev_flags)
80 {
81         struct event_queue *ev_q = get_event_q();
82         if (ev_flags & EVENT_VCORE_PRIVATE)
83                 ev_q->ev_mbox = &vcpd_of(vcoreid)->ev_mbox_private;
84         else
85                 ev_q->ev_mbox = &vcpd_of(vcoreid)->ev_mbox_public;
86         return ev_q;
87 }
88
89 void put_event_q(struct event_queue *ev_q)
90 {
91         /* if we use something other than malloc, we'll need to be aware that ev_q
92          * is not an event_queue_big. */
93         free(ev_q);
94 }
95
96 /* Sets ev_q to be the receiving end for kernel event ev_type */
97 void register_kevent_q(struct event_queue *ev_q, unsigned int ev_type)
98 {
99         __procdata.kernel_evts[ev_type] = ev_q;
100 }
101
102 /* Clears the event, returning an ev_q if there was one there.  You'll need to
103  * free it. */
104 struct event_queue *clear_kevent_q(unsigned int ev_type)
105 {
106         struct event_queue *ev_q = __procdata.kernel_evts[ev_type];
107         __procdata.kernel_evts[ev_type] = 0;
108         return ev_q;
109 }
110
111 /* Enables an IPI/event combo for ev_type sent to vcoreid's default mbox.  IPI
112  * if you want one or not.  If you want the event to go to the vcore private
113  * mbox (meaning no other core should ever handle it), send in
114  * EVENT_VCORE_PRIVATE with ev_flags.
115  *
116  * This is the simplest thing applications may want, and shows how you can put
117  * the other event functions together to get similar things done. */
118 void enable_kevent(unsigned int ev_type, uint32_t vcoreid, int ev_flags)
119 {
120         struct event_queue *ev_q = get_event_q_vcpd(vcoreid, ev_flags);
121         ev_q->ev_flags = ev_flags;
122         ev_q->ev_vcore = vcoreid;
123         ev_q->ev_handler = 0;
124         wmb();  /* make sure ev_q is filled out before registering */
125         register_kevent_q(ev_q, ev_type);
126 }
127
128 /* Stop receiving the events (one could be on the way).  Caller needs to be
129  * careful, since the kernel might be sending an event to the ev_q.  Depending
130  * on the ev_q, it may be hard to know when it is done (for instance, if all
131  * syscalls you ever registered with the ev_q are done, then it would be okay).
132  * o/w, don't free it. */
133 struct event_queue *disable_kevent(unsigned int ev_type)
134 {
135         return clear_kevent_q(ev_type);
136 }
137
138 /********* Event Handling / Reception ***********/
139 /* Somewhat ghetto helper, for the lazy.  If all you care about is an event
140  * number, this will see if the event happened or not.  It will try for a
141  * message, but if there is none, it will go for a bit.  Note that multiple
142  * bit messages will turn into just one bit. */
143 unsigned int get_event_type(struct event_mbox *ev_mbox)
144 {
145         struct event_msg local_msg = {0};
146         /* UCQ returns 0 on success, so this will dequeue and return the type. */
147         if (!get_ucq_msg(&ev_mbox->ev_msgs, &local_msg)) {
148                 return local_msg.ev_type;
149         }
150         if (BITMASK_IS_CLEAR(&ev_mbox->ev_bitmap, MAX_NR_EVENT))
151                 return EV_NONE; /* aka, 0 */
152         for (int i = 0; i < MAX_NR_EVENT; i++) {
153                 if (GET_BITMASK_BIT(ev_mbox->ev_bitmap, i)) {
154                         CLR_BITMASK_BIT_ATOMIC(ev_mbox->ev_bitmap, i);
155                         return i;
156                 }
157         }
158         return EV_NONE;
159 }
160
161 /* Actual Event Handling */
162
163 /* List of handlers, process-wide, that the 2LS should fill in.  They all must
164  * return (don't context switch to a u_thread) */
165 handle_event_t ev_handlers[MAX_NR_EVENT] = {[EV_EVENT] handle_ev_ev, 0};
166
167 /* Handles all the messages in the mbox, but not the single bits.  Returns the
168  * number handled. */
169 static int handle_mbox_msgs(struct event_mbox *ev_mbox)
170 {
171         int retval = 0;
172         struct event_msg local_msg;
173         unsigned int ev_type;
174         uint32_t vcoreid = vcore_id();
175         /* Try to dequeue, dispatch whatever you get. */
176         while (!get_ucq_msg(&ev_mbox->ev_msgs, &local_msg)) {
177                 ev_type = local_msg.ev_type;
178                 printd("[event] UCQ (mbox %08p), ev_type: %d\n", ev_mbox, ev_type);
179                 if (ev_handlers[ev_type])
180                         ev_handlers[ev_type](&local_msg, ev_type);
181                 check_preempt_pending(vcoreid);
182                 retval++;
183         }
184         return retval;
185 }
186
187 /* Handle an mbox.  This is the receive-side processing of an event_queue.  It
188  * takes an ev_mbox, since the vcpd mbox isn't a regular ev_q.  For now, we
189  * check for preemptions between each event handler. */
190 int handle_mbox(struct event_mbox *ev_mbox)
191 {
192         int retval = 0;
193         uint32_t vcoreid = vcore_id();
194         void bit_handler(unsigned int bit) {
195                 printd("[event] Bit: ev_type: %d\n", bit);
196                 if (ev_handlers[bit])
197                         ev_handlers[bit](0, bit);
198                 retval++;
199                 check_preempt_pending(vcoreid);
200                 /* Consider checking the queue for incoming messages while we're here */
201         }
202         printd("[event] handling ev_mbox %08p on vcore %d\n", ev_mbox, vcore_id());
203         /* Handle full messages. */
204         retval = handle_mbox_msgs(ev_mbox);
205         /* Process all bits, if the kernel tells us any bit is set.  We don't clear
206          * the flag til after we check everything, in case one of the handlers
207          * doesn't return.  After we clear it, we recheck. */
208         if (ev_mbox->ev_check_bits) {
209                 do {
210                         ev_mbox->ev_check_bits = TRUE;  /* in case we don't return */
211                         cmb();
212                         BITMASK_FOREACH_SET(ev_mbox->ev_bitmap, MAX_NR_EVENT, bit_handler,
213                                             TRUE);
214                         ev_mbox->ev_check_bits = FALSE;
215                         wrmb(); /* check_bits written before we check for it being clear */
216                 } while (!BITMASK_IS_CLEAR(ev_mbox->ev_bitmap, MAX_NR_EVENT));
217         }
218         return retval;
219 }
220
221 /* Empty if the UCQ is empty and the bits don't need checked */
222 bool mbox_is_empty(struct event_mbox *ev_mbox)
223 {
224         return (ucq_is_empty(&ev_mbox->ev_msgs) && (!ev_mbox->ev_check_bits));
225 }
226
227 /* The EV_EVENT handler - extract the ev_q from the message. */
228 void handle_ev_ev(struct event_msg *ev_msg, unsigned int ev_type)
229 {
230         struct event_queue *ev_q;
231         /* EV_EVENT can't handle not having a message / being a bit.  If we got a
232          * bit message, it's a bug somewhere */
233         assert(ev_msg);
234         ev_q = ev_msg->ev_arg3;
235         /* Same deal, a null ev_q is probably a bug, or someone being a jackass */
236         assert(ev_q);
237         /* Clear pending, so we can start getting INDIRs and IPIs again.  We must
238          * set this before (compared to handle_events, then set it, then handle
239          * again), since there is no guarantee handle_event_q() will return.  If
240          * there is a pending preemption, the vcore quickly yields and will deal
241          * with the remaining events in the future - meaning it won't return to
242          * here. */
243         ev_q->ev_alert_pending = FALSE;
244         wmb();  /* don't let the pending write pass the signaling of an ev recv */
245         handle_event_q(ev_q);
246 }
247
248 /* 2LS will probably call this in vcore_entry and places where it wants to check
249  * for / handle events.  This will process all the events for the given vcore.
250  * Note, it probably should be the calling vcore you do this to...  Returns the
251  * number of events handled. */
252 int handle_events(uint32_t vcoreid)
253 {
254         struct preempt_data *vcpd = vcpd_of(vcoreid);
255         int retval = 0;
256         retval += handle_mbox(&vcpd->ev_mbox_private);
257         retval += handle_mbox(&vcpd->ev_mbox_public);
258         return retval;
259 }
260
261 /* Handles the events on ev_q IAW the event_handlers[].  If the ev_q is
262  * application specific, then this will dispatch/handle based on its flags. */
263 void handle_event_q(struct event_queue *ev_q)
264 {
265         /* If the program wants to handle the ev_q on its own: */
266         if (ev_q->ev_flags & (EVENT_JUSTHANDLEIT | EVENT_THREAD)) {
267                 if (!ev_q->ev_handler) {
268                         printf("No ev_handler installed for ev_q %08p, aborting!\n", ev_q);
269                         return;
270                 }
271                 if (ev_q->ev_flags & EVENT_JUSTHANDLEIT) {
272                         /* Remember this can't block or page fault */
273                         ev_q->ev_handler(ev_q);
274                 } else if (ev_q->ev_flags & EVENT_THREAD) {
275                         /* 2LS sched op.  The 2LS can use an existing thread if it wants,
276                          * but do so inside spawn_thread() */
277                         if (sched_ops->spawn_thread)
278                                 sched_ops->spawn_thread((uintptr_t)ev_q->ev_handler, ev_q);
279                         else
280                                 printf("2LS can't spawn a thread for ev_q %08p\n", ev_q);
281                 }
282                 return;
283         }
284         printd("[event] handling ev_q %08p on vcore %d\n", ev_q, vcore_id());
285         handle_mbox(ev_q->ev_mbox);
286 }