Allows application-specific event handling (XCC)
authorBarret Rhoden <brho@cs.berkeley.edu>
Fri, 25 Feb 2011 22:03:00 +0000 (14:03 -0800)
committerKevin Klues <klueska@cs.berkeley.edu>
Thu, 3 Nov 2011 00:35:59 +0000 (17:35 -0700)
Programs can assign ev_handlers to an event queue.  Mostly untested, for
now.

Reinstall your kernel headers.

Documentation/async_events.txt
kern/include/ros/event.h
tests/syscall.c
user/parlib/event.c
user/parlib/include/event.h
user/parlib/include/vcore.h

index f678aff..0bf95c3 100644 (file)
@@ -243,21 +243,27 @@ thread can want to run its own handler, perhaps because it performs its own
 asynchronous I/O (compared to relying on the 2LS to schedule synchronous
 blocking u_threads).
 
-There are a couple ways to handle this.  Ultimately, the application is
-supposed to handle the event.  If it asked for an IPI, it is because something
-ought to be done, which really means running a handler.  If the application
-sets EV_THREAD in the ev_q's flags, the 2LS ought to spawn a thread to run the
-ev_q's handler.  If EV_JUSTHANDLEIT is set, the vcore will execute the handler
-itself.  Careful with this, since the only memory it touches must be pinned,
-the function must not block (this is only true for the handlers called
+There are a couple ways to handle this.  Ultimately, the application is supposed
+to handle the event.  If it asked for an IPI, it is because something ought to
+be done, which really means running a handler.  If the application sets
+EVENT_THREAD in the ev_q's flags, the 2LS ought to spawn a thread to run the
+ev_q's handler.  If EVENT_JUSTHANDLEIT is set, the vcore will execute the
+handler itself.  Careful with this, since the only memory it touches must be
+pinned, the function must not block (this is only true for the handlers called
 directly out of vcore context), and it should return quickly.
 
 Note that in either case, vcore-written code (library code) does not look at
-the contents of the notification event.  Also Note the handler takes the whole
+the contents of the notification event.  Also note the handler takes the whole
 event_queue, and not a specific message.  It is more flexible, can handle
-multiple specific events, and doesn't require the vcore code to dequeue and
+multiple specific events, and doesn't require the vcore code to dequeue the
 event and either pass by value or allocate more memory.
 
+These ev_q handlers are different than ev_handlers.  The former handles an
+event_queue.  The latter is the 2LS's way to handle specific types of messages.
+If an app wants to process specific messages, have them sent to an ev_q under
+its control; don't mess with ev_handlers unless you're the 2LS (or example
+code).
+
 Continuing the analogy between vcores getting IPIs and the OS getting HW
 interrupts, what goes on in vcore context is like what goes on in interrupt
 context, and the threaded handler is like running a threaded interrupt handler
index 06789c1..7cabd9d 100644 (file)
 #include <ros/bcq_struct.h>
 #include <ros/arch/trapframe.h>
 
-/* Event Delivery Flags. */
+/* Event Delivery Flags from the process to the kernel */
 #define EVENT_IPI                              0x001   /* IPI the core */
 #define EVENT_NOMSG                            0x002   /* just send the bit, not the msg */
 #define EVENT_ROUNDROBIN               0x004   /* pick a vcore, RR style */
 #define EVENT_VCORE_APPRO              0x008   /* send to where the kernel wants */
+/* Flags from the program to the 2LS */
+#define EVENT_JUSTHANDLEIT             0x00c   /* 2LS should handle the ev_q */
+#define EVENT_THREAD                   0x010   /* spawn thread to handle ev_q */
 
 /* Event Message Types */
 #define EV_NONE                                         0
index 461f4a9..6a12009 100644 (file)
@@ -35,10 +35,11 @@ int main(int argc, char** argv)
        while (!(sysc.flags & SC_DONE))
                cpu_relax();
        #endif
-       /* But let's check on events...  Handle event_q returns how many events it
-        * handled.  Want to spin in this testing code. */
-       while(!handle_event_q(ev_q))
+       /* But let's check on events...  Spin til something happened, then handle
+        * events.  This method is just used for this testing code. */
+       while (!event_activity(ev_q->ev_mbox, ev_q->ev_flags))
                cpu_relax();
+       handle_event_q(ev_q);
        /* by now, we should have run our handler */
        /********************************************************/
        /* Start MCP / IPI test */
index 16df0f6..47a4444 100644 (file)
@@ -215,9 +215,8 @@ void handle_ev_ev(struct event_msg *ev_msg, unsigned int ev_type, bool overflow)
        if (!ev_msg)
                return;
        ev_q = ev_msg->ev_arg3;
-       if (!ev_q)
-               return;
-       handle_mbox(ev_q->ev_mbox, ev_q->ev_flags);
+       if (ev_q)
+               handle_event_q(ev_q);
 }
 
 /* 2LS will probably call this in vcore_entry and places where it wants to check
@@ -231,12 +230,30 @@ int handle_events(uint32_t vcoreid)
         * whether or not the 2LS has a NOMSG ev_q pointing to its vcpd, or have the
         * kernel set another flag for "bits" */
        return handle_mbox(&vcpd->ev_mbox, EVENT_NOMSG);
-
 }
 
-/* Handles the events on ev_q IAW the event_handlers[].  Returns the number of
- * events handled. */
-int handle_event_q(struct event_queue *ev_q)
+/* Handles the events on ev_q IAW the event_handlers[].  If the ev_q is
+ * application specific, then this will dispatch/handle based on its flags. */
+void handle_event_q(struct event_queue *ev_q)
 {
-       return handle_mbox(ev_q->ev_mbox, ev_q->ev_flags);
+       /* If the program wants to handle the ev_q on its own: */
+       if (ev_q->ev_flags & (EVENT_JUSTHANDLEIT | EVENT_THREAD)) {
+               if (!ev_q->ev_handler) {
+                       printf("No ev_handler installed for ev_q %08p, aborting!\n", ev_q);
+                       return;
+               }
+               if (ev_q->ev_flags & EVENT_JUSTHANDLEIT) {
+                       /* Remember this can't block or page fault */
+                       ev_q->ev_handler(ev_q);
+               } else if (ev_q->ev_flags & EVENT_THREAD) {
+                       /* 2LS sched op.  The 2LS can use an existing thread if it wants,
+                        * but do so inside spawn_thread() */
+                       if (sched_ops->spawn_thread)
+                               sched_ops->spawn_thread((uintptr_t)ev_q->ev_handler, ev_q);
+                       else
+                               printf("2LS can't spawn a thread for ev_q %08p\n", ev_q);
+               }
+               return;
+       }
+       handle_mbox(ev_q->ev_mbox, ev_q->ev_flags);
 }
index 7f2962a..fe0bb03 100644 (file)
@@ -35,6 +35,6 @@ extern handle_event_t ev_handlers[];
 void handle_ev_ev(struct event_msg *ev_msg, unsigned int ev_type,
                   bool overflow);
 int handle_events(uint32_t vcoreid);
-int handle_event_q(struct event_queue *ev_q);
+void handle_event_q(struct event_queue *ev_q);
 
 #endif /* _EVENT_H */
index 000fb79..7111d56 100644 (file)
@@ -29,6 +29,7 @@ extern "C" {
 /* 2L-Scheduler operations.  Can be 0. */
 struct schedule_ops {
        void (*preempt_pending)(void);
+       void (*spawn_thread)(uintptr_t pc_start, void *data);   /* don't run yet */
 };
 extern struct schedule_ops *sched_ops;