enable_kevent() takes flags, not a bool
[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 <ros/bcq.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
20 /********* Event_q Setup / Registration  ***********/
21
22 /* Get event_qs via these interfaces, since eventually we'll want to either
23  * allocate from pinned memory or use some form of a slab allocator.  Also, this
24  * stitches up the big_q so its ev_mbox points to its internal mbox.  Never
25  * access the internal mbox directly. */
26 struct event_queue *get_big_event_q(void)
27 {
28         /* TODO: (PIN) should be pinned memory */
29         struct event_queue_big *big_q = malloc(sizeof(struct event_queue_big));
30         memset(big_q, 0, sizeof(struct event_queue_big));
31         big_q->ev_mbox = &big_q->ev_imbox;
32         return (struct event_queue*)big_q;
33 }
34
35 /* Give it up */
36 void put_big_event_q(struct event_queue *ev_q)
37 {
38         /* if we use something other than malloc, we'll need to be aware that ev_q
39          * is actually an event_queue_big.  One option is to use the flags, though
40          * this could be error prone. */
41         free(ev_q);
42 }
43
44 /* Need to point this event_q to an mbox - usually to a vcpd */
45 struct event_queue *get_event_q(void)
46 {
47         /* TODO: (PIN) should be pinned memory */
48         struct event_queue *ev_q = malloc(sizeof(struct event_queue));
49         memset(ev_q, 0, sizeof(struct event_queue));
50         return ev_q;
51 }
52
53 /* Gets a small ev_q, with ev_mbox pointing to the vcpd mbox of vcoreid */
54 struct event_queue *get_event_q_vcpd(uint32_t vcoreid)
55 {
56         struct event_queue *ev_q = get_event_q();
57         ev_q->ev_mbox = &__procdata.vcore_preempt_data[vcoreid].ev_mbox;
58         return ev_q;
59 }
60
61 void put_event_q(struct event_queue *ev_q)
62 {
63         /* if we use something other than malloc, we'll need to be aware that ev_q
64          * is actually an event_queue_big. */
65         free(ev_q);
66 }
67
68 /* Sets ev_q to be the receiving end for kernel event ev_type */
69 void register_kevent_q(struct event_queue *ev_q, unsigned int ev_type)
70 {
71         __procdata.kernel_evts[ev_type] = ev_q;
72 }
73
74 /* Clears the event, returning an ev_q if there was one there.  You'll need to
75  * free it. */
76 struct event_queue *clear_kevent_q(unsigned int ev_type)
77 {
78         struct event_queue *ev_q = __procdata.kernel_evts[ev_type];
79         __procdata.kernel_evts[ev_type] = 0;
80         return ev_q;
81 }
82
83 /* Enables an IPI/event combo for ev_type sent to vcoreid's default mbox.  IPI
84  * if you want one or not.  This is the simplest thing applications may want,
85  * and shows how you can put the other event functions together to get similar
86  * things done. */
87 void enable_kevent(unsigned int ev_type, uint32_t vcoreid, int ev_flags)
88 {
89         struct event_queue *ev_q = get_event_q_vcpd(vcoreid);
90         ev_q->ev_flags = ev_flags;
91         ev_q->ev_vcore = vcoreid;
92         ev_q->ev_handler = 0;
93         register_kevent_q(ev_q, ev_type);
94 }
95
96 /* Stop receiving the events (one could be on the way) */
97 void disable_kevent(unsigned int ev_type)
98 {
99         struct event_queue *ev_q = clear_kevent_q(ev_type);
100         if (ev_q)
101                 put_event_q(ev_q);
102         else
103                 printf("Tried to disable but no event_q loaded on ev_type %d", ev_type);
104 }
105
106 /********* Event Handling / Reception ***********/
107 /* Tests the ev_q to see if anything has happened on it.  Up to the caller to do
108  * something with the info, such as try and dequeue or handle an overflow.
109  * Flags is for the ev_q's flags (if you know it), which is to check the NO_MSG
110  * style ev_qs. */
111 bool event_activity(struct event_mbox *ev_mbox, int flags)
112 {
113         if (!bcq_empty(&ev_mbox->ev_msgs))
114                 return TRUE;
115         /* Only need to check the bitmask for activity if we've had overflows or if
116          * we are a NO_MSG.  This means the client can clear its overflows. */
117         if (ev_mbox->ev_overflows || (flags & EVENT_NOMSG)) {
118                 if (!BITMASK_IS_CLEAR(&ev_mbox->ev_bitmap, MAX_NR_EVENT))
119                         return TRUE;
120         }
121         return FALSE;
122 }
123
124 /* Clears the overflows, returning the number of overflows cleared. */
125 unsigned int event_clear_overflows(struct event_queue *ev_q)
126 {
127         unsigned int retval = ev_q->ev_mbox->ev_overflows;
128         ev_q->ev_mbox->ev_overflows = 0;
129         return retval;
130 }
131
132 /* Somewhat ghetto helper, for the lazy.  If all you care about is an event
133  * number, this will see if the event happened or not.  It will try for a
134  * message, but if there is none, it will go for a bit.  Note that multiple
135  * messages that overflowed could turn into just one bit. */
136 unsigned int get_event_type(struct event_mbox *ev_mbox)
137 {
138         struct event_msg local_msg = {0};
139         if (bcq_dequeue(&ev_mbox->ev_msgs, &local_msg, NR_BCQ_EVENTS)) {
140                 return local_msg.ev_type;
141         }
142         if (BITMASK_IS_CLEAR(&ev_mbox->ev_bitmap, MAX_NR_EVENT))
143                 return EV_NONE; /* aka, 0 */
144         for (int i = 0; i < MAX_NR_EVENT; i++) {
145                 if (GET_BITMASK_BIT(ev_mbox->ev_bitmap, i)) {
146                         CLR_BITMASK_BIT_ATOMIC(ev_mbox->ev_bitmap, i);
147                         return i;
148                 }
149         }
150         return EV_NONE;
151 }
152
153 /* Actual Event Handling */
154
155 /* List of handlers, process-wide, that the 2LS should fill in.  They all must
156  * return (don't context switch to a u_thread), and need to handle ev_msg being
157  * 0. */
158 handle_event_t ev_handlers[MAX_NR_EVENT] = {[EV_EVENT] handle_ev_ev, 0};
159
160 /* Handle an mbox.  This is the receive-side processing of an event_queue.  It
161  * takes an ev_mbox, since the vcpd mbox isn't a regular ev_q.  For now, we
162  * check for preemptions between each event handler. */
163 static int handle_mbox(struct event_mbox *ev_mbox, unsigned int flags)
164 {
165         struct event_msg local_msg;
166         unsigned int ev_type;
167         bool overflow = FALSE;
168         int retval = 0;
169         uint32_t vcoreid = vcore_id();
170
171         if (!event_activity(ev_mbox, flags))
172                 return retval;
173         /* Try to dequeue, dispatch whatever you get.  TODO consider checking for
174          * overflow first */
175         while (!bcq_dequeue(&ev_mbox->ev_msgs, &local_msg, NR_BCQ_EVENTS)) {
176                 ev_type = local_msg.ev_type;
177                 printd("BCQ: ev_type: %d\n", ev_type);
178                 if (ev_handlers[ev_type])
179                         ev_handlers[ev_type](&local_msg, overflow);
180                 check_preempt_pending(vcoreid);
181                 retval++;
182         }
183         /* Race here with another core clearing overflows/bits.  Don't have more
184          * than one vcore work on an mbox without being more careful of overflows
185          * (as in, assume any overflow means all bits must be checked, since someone
186          * might have not told a handler of an overflow). */
187         if (ev_mbox->ev_overflows) {
188                 ev_mbox->ev_overflows = 0;
189                 overflow = TRUE;
190         }
191         /* Process all bits.  As far as I've seen, using overflow like this is
192          * thread safe (tested on some code in mhello, asm looks like it knows to
193          * have the function use addresses relative to the frame pointer). */
194         void bit_handler(unsigned int bit) {
195                 printd("Bit: ev_type: %d\n", ev_type);
196                 if (ev_handlers[bit])
197                         ev_handlers[bit](0, overflow);
198                 retval++;
199                 check_preempt_pending(vcoreid);
200                 /* Consider checking the queue for incoming messages while we're here */
201         }
202         BITMASK_FOREACH_SET(ev_mbox->ev_bitmap, MAX_NR_EVENT, bit_handler, TRUE);
203         return retval;
204 }
205
206 /* The EV_EVENT handler - extract the ev_q from the message.  If you want this
207  * to catch overflows, you'll need to register your event_queues (TODO).  Might
208  * be issues with per-core handling (register globally, or just per vcore). */
209 void handle_ev_ev(struct event_msg *ev_msg, bool overflow)
210 {
211         struct event_queue *ev_q;
212         /* TODO: handle overflow (register, etc) */
213         if (overflow)
214                 printf("Ignoring overflow!  Deal with me!\n");
215         if (!ev_msg)
216                 return;
217         ev_q = ev_msg->ev_arg3;
218         if (!ev_q)
219                 return;
220         handle_mbox(ev_q->ev_mbox, ev_q->ev_flags);
221 }
222
223 /* 2LS will probably call this in vcore_entry and places where it wants to check
224  * for / handle events.  This will process all the events for the given vcore.
225  * Note, it probably should be the calling vcore you do this to...  Returns the
226  * number of events handled. */
227 int handle_events(uint32_t vcoreid)
228 {
229         struct preempt_data *vcpd = &__procdata.vcore_preempt_data[vcoreid];
230         /* TODO: EVENT_NOMSG checks could be painful.  we could either keep track of
231          * whether or not the 2LS has a NOMSG ev_q pointing to its vcpd, or have the
232          * kernel set another flag for "bits" */
233         return handle_mbox(&vcpd->ev_mbox, EVENT_NOMSG);
234
235 }
236
237 /* Handles the events on ev_q IAW the event_handlers[].  Returns the number of
238  * events handled. */
239 int handle_event_q(struct event_queue *ev_q)
240 {
241         return handle_mbox(ev_q->ev_mbox, ev_q->ev_flags);
242 }