Replaces BCQs with UCQs (XCC)
[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, this
25  * stitches up the big_q so its ev_mbox points to its internal mbox.  Never
26  * access the internal mbox directly. */
27 struct event_queue *get_big_event_q(void)
28 {
29         /* TODO: (PIN) should be pinned memory */
30         struct event_queue_big *big_q = malloc(sizeof(struct event_queue_big));
31         memset(big_q, 0, sizeof(struct event_queue_big));
32         big_q->ev_mbox = &big_q->ev_imbox;
33         return (struct event_queue*)big_q;
34 }
35
36 /* Give it up */
37 void put_big_event_q(struct event_queue *ev_q)
38 {
39         /* if we use something other than malloc, we'll need to be aware that ev_q
40          * is actually an event_queue_big.  One option is to use the flags, though
41          * this could be error prone. */
42         free(ev_q);
43 }
44
45 /* Need to point this event_q to an mbox - usually to a vcpd */
46 struct event_queue *get_event_q(void)
47 {
48         /* TODO: (PIN) should be pinned memory */
49         struct event_queue *ev_q = malloc(sizeof(struct event_queue));
50         memset(ev_q, 0, sizeof(struct event_queue));
51         return ev_q;
52 }
53
54 /* Gets a small ev_q, with ev_mbox pointing to the vcpd mbox of vcoreid */
55 struct event_queue *get_event_q_vcpd(uint32_t vcoreid)
56 {
57         struct event_queue *ev_q = get_event_q();
58         ev_q->ev_mbox = &__procdata.vcore_preempt_data[vcoreid].ev_mbox;
59         return ev_q;
60 }
61
62 void put_event_q(struct event_queue *ev_q)
63 {
64         /* if we use something other than malloc, we'll need to be aware that ev_q
65          * is actually an event_queue_big. */
66         free(ev_q);
67 }
68
69 /* Sets ev_q to be the receiving end for kernel event ev_type */
70 void register_kevent_q(struct event_queue *ev_q, unsigned int ev_type)
71 {
72         __procdata.kernel_evts[ev_type] = ev_q;
73 }
74
75 /* Clears the event, returning an ev_q if there was one there.  You'll need to
76  * free it. */
77 struct event_queue *clear_kevent_q(unsigned int ev_type)
78 {
79         struct event_queue *ev_q = __procdata.kernel_evts[ev_type];
80         __procdata.kernel_evts[ev_type] = 0;
81         return ev_q;
82 }
83
84 /* Enables an IPI/event combo for ev_type sent to vcoreid's default mbox.  IPI
85  * if you want one or not.  This is the simplest thing applications may want,
86  * and shows how you can put the other event functions together to get similar
87  * things done. */
88 void enable_kevent(unsigned int ev_type, uint32_t vcoreid, int ev_flags)
89 {
90         struct event_queue *ev_q = get_event_q_vcpd(vcoreid);
91         ev_q->ev_flags = ev_flags;
92         ev_q->ev_vcore = vcoreid;
93         ev_q->ev_handler = 0;
94         register_kevent_q(ev_q, ev_type);
95 }
96
97 /* Stop receiving the events (one could be on the way) */
98 void disable_kevent(unsigned int ev_type)
99 {
100         struct event_queue *ev_q = clear_kevent_q(ev_type);
101         if (ev_q)
102                 put_event_q(ev_q);
103         else
104                 printf("Tried to disable but no event_q loaded on ev_type %d", ev_type);
105 }
106
107 /********* Event Handling / Reception ***********/
108 /* Clears the overflows, returning the number of overflows cleared. */
109 unsigned int event_clear_overflows(struct event_queue *ev_q)
110 {
111         unsigned int retval = ev_q->ev_mbox->ev_overflows;
112         ev_q->ev_mbox->ev_overflows = 0;
113         return retval;
114 }
115
116 /* Somewhat ghetto helper, for the lazy.  If all you care about is an event
117  * number, this will see if the event happened or not.  It will try for a
118  * message, but if there is none, it will go for a bit.  Note that multiple
119  * messages that overflowed could turn into just one bit. */
120 unsigned int get_event_type(struct event_mbox *ev_mbox)
121 {
122         struct event_msg local_msg = {0};
123         /* UCQ returns 0 on success, so this will dequeue and return the type. */
124         if (!get_ucq_msg(&ev_mbox->ev_msgs, &local_msg)) {
125                 return local_msg.ev_type;
126         }
127         if (BITMASK_IS_CLEAR(&ev_mbox->ev_bitmap, MAX_NR_EVENT))
128                 return EV_NONE; /* aka, 0 */
129         for (int i = 0; i < MAX_NR_EVENT; i++) {
130                 if (GET_BITMASK_BIT(ev_mbox->ev_bitmap, i)) {
131                         CLR_BITMASK_BIT_ATOMIC(ev_mbox->ev_bitmap, i);
132                         return i;
133                 }
134         }
135         return EV_NONE;
136 }
137
138 /* Actual Event Handling */
139
140 /* List of handlers, process-wide, that the 2LS should fill in.  They all must
141  * return (don't context switch to a u_thread), and need to handle ev_msg being
142  * 0. */
143 handle_event_t ev_handlers[MAX_NR_EVENT] = {[EV_EVENT] handle_ev_ev, 0};
144
145 /* Handles all the messages in the mbox, but not the single bits.  Currently
146  * this doesn't tell the handler about overflow, since you should be handling
147  * that because of the bits.  Returns the number handled. */
148 int handle_mbox_msgs(struct event_mbox *ev_mbox)
149 {
150         int retval = 0;
151         struct event_msg local_msg;
152         unsigned int ev_type;
153         uint32_t vcoreid = vcore_id();
154         /* Try to dequeue, dispatch whatever you get. */
155         while (!get_ucq_msg(&ev_mbox->ev_msgs, &local_msg)) {
156                 ev_type = local_msg.ev_type;
157                 printd("UCQ: ev_type: %d\n", ev_type);
158                 if (ev_handlers[ev_type])
159                         ev_handlers[ev_type](&local_msg, ev_type, FALSE);       /* no overflow*/
160                 check_preempt_pending(vcoreid);
161                 retval++;
162         }
163         return retval;
164 }
165
166 /* Handle an mbox.  This is the receive-side processing of an event_queue.  It
167  * takes an ev_mbox, since the vcpd mbox isn't a regular ev_q.  For now, we
168  * check for preemptions between each event handler. */
169 static int handle_mbox(struct event_mbox *ev_mbox, unsigned int flags)
170 {
171         bool overflow = FALSE;
172         int retval = 0;
173         uint32_t vcoreid = vcore_id();
174
175         /* Handle full messages.  Will deal with overflow and bits later. */
176         retval = handle_mbox_msgs(ev_mbox);
177
178         /* Race here with another core clearing overflows/bits.  Don't have more
179          * than one vcore work on an mbox without being more careful of overflows
180          * (as in, assume any overflow means all bits must be checked, since someone
181          * might have not told a handler of an overflow).
182          *
183          * The purpose of this is to let everyone know we are dealing with
184          * overflows, mostly for preventing code from freaking out about having too
185          * many overflows.  Also slightly important to not have wraparound (though
186          * in theory it is still possible). */
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", bit);
196                 cmb();
197                 if (ev_handlers[bit])
198                         ev_handlers[bit](0, bit, overflow || ev_mbox->ev_overflows);
199                 retval++;
200                 check_preempt_pending(vcoreid);
201                 /* Consider checking the queue for incoming messages while we're here */
202         }
203         BITMASK_FOREACH_SET(ev_mbox->ev_bitmap, MAX_NR_EVENT, bit_handler, TRUE);
204         /* If you ever have bugs where bits are set without overflow (for
205          * non-EVENT_NOMSG handlers, like the syscall, check here for the bit being
206          * set AND there is no overflow.  You must read the bit before checking
207          * the overflows, since the kernel writes them in the other order (kernel
208          * sets overflow, then sets the bit). */
209         return retval;
210 }
211
212 /* The EV_EVENT handler - extract the ev_q from the message.  If you want this
213  * to catch overflows, you'll need to register your event_queues (TODO).  Might
214  * be issues with per-core handling (register globally, or just per vcore). */
215 void handle_ev_ev(struct event_msg *ev_msg, unsigned int ev_type, bool overflow)
216 {
217         struct event_queue *ev_q;
218         /* TODO: handle overflow (register, etc) */
219         if (overflow)
220                 printf("Ignoring overflow!  Deal with me!\n");
221         if (!ev_msg)
222                 return;
223         ev_q = ev_msg->ev_arg3;
224         if (ev_q)
225                 handle_event_q(ev_q);
226 }
227
228 /* 2LS will probably call this in vcore_entry and places where it wants to check
229  * for / handle events.  This will process all the events for the given vcore.
230  * Note, it probably should be the calling vcore you do this to...  Returns the
231  * number of events handled. */
232 int handle_events(uint32_t vcoreid)
233 {
234         struct preempt_data *vcpd = &__procdata.vcore_preempt_data[vcoreid];
235         /* TODO: EVENT_NOMSG checks could be painful.  we could either keep track of
236          * whether or not the 2LS has a NOMSG ev_q pointing to its vcpd, or have the
237          * kernel set another flag for "bits" */
238         return handle_mbox(&vcpd->ev_mbox, EVENT_NOMSG);
239 }
240
241 /* Handles the events on ev_q IAW the event_handlers[].  If the ev_q is
242  * application specific, then this will dispatch/handle based on its flags. */
243 void handle_event_q(struct event_queue *ev_q)
244 {
245         /* If the program wants to handle the ev_q on its own: */
246         if (ev_q->ev_flags & (EVENT_JUSTHANDLEIT | EVENT_THREAD)) {
247                 if (!ev_q->ev_handler) {
248                         printf("No ev_handler installed for ev_q %08p, aborting!\n", ev_q);
249                         return;
250                 }
251                 if (ev_q->ev_flags & EVENT_JUSTHANDLEIT) {
252                         /* Remember this can't block or page fault */
253                         ev_q->ev_handler(ev_q);
254                 } else if (ev_q->ev_flags & EVENT_THREAD) {
255                         /* 2LS sched op.  The 2LS can use an existing thread if it wants,
256                          * but do so inside spawn_thread() */
257                         if (sched_ops->spawn_thread)
258                                 sched_ops->spawn_thread((uintptr_t)ev_q->ev_handler, ev_q);
259                         else
260                                 printf("2LS can't spawn a thread for ev_q %08p\n", ev_q);
261                 }
262                 return;
263         }
264         handle_mbox(ev_q->ev_mbox, ev_q->ev_flags);
265 }