2LS handles pending preemptions
authorBarret Rhoden <brho@cs.berkeley.edu>
Thu, 24 Feb 2011 20:18:15 +0000 (12:18 -0800)
committerKevin Klues <klueska@cs.berkeley.edu>
Thu, 3 Nov 2011 00:35:58 +0000 (17:35 -0700)
Initial 2LS schedule_ops, one of which is a sched-specific way to deal
with a pending preemption.

tests/mhello.c
tests/syscall.c
user/parlib/event.c
user/parlib/include/vcore.h
user/parlib/vcore.c
user/pthread/pthread.c

index 49f07e5..00c982f 100644 (file)
@@ -62,7 +62,7 @@ int main(int argc, char** argv)
 
        /* don't forget to enable notifs on vcore0 at some point */
        enable_notifs(0);
-       
+
 /* end: stuff userspace needs to do before switching to multi-mode */
 
        if ((vcoreid = vcore_id())) {
@@ -123,20 +123,15 @@ void vcore_entry(void)
        temp = 0xcafebabe;
 /* begin: stuff userspace needs to do to handle notifications */
 
-       struct vcore *vc = &__procinfo.vcoremap[vcoreid];
        struct preempt_data *vcpd;
        vcpd = &__procdata.vcore_preempt_data[vcoreid];
-       
+
+       /* checks if a preempt is pending, yields if so */
+       check_preempt_pending(vcoreid);
+
        /* here is how you receive an event */
        handle_events(vcoreid);
 
-       /* how we tell a preemption is pending (regardless of notif/events) */
-       if (vc->preempt_pending) {
-               printf("Oh crap, vcore %d is being preempted!  Yielding\n", vcoreid);
-               sys_yield(TRUE);
-               printf("After yield on vcore %d. I wasn't being preempted.\n", vcoreid);
-       }
-               
        /* Lets try to restart vcore0's context.  Note this doesn't do anything to
         * set the appropriate TLS.  On x86, this will involve changing the LDT
         * entry for this vcore to point to the TCB of the new user-thread. */
@@ -160,13 +155,13 @@ void vcore_entry(void)
                /* Load silly state (Floating point) too */
                pop_ros_tf(&vcpd->notif_tf, vcoreid);
                panic("should never see me!");
-       }       
+       }
        /* unmask notifications once you can let go of the notif_tf and it is okay
         * to clobber the transition stack.
         * Check Documentation/processes.txt: 4.2.4.  In real code, you should be
         * popping the tf of whatever user process you want (get off the x-stack) */
        enable_notifs(vcoreid);
-       
+
 /* end: stuff userspace needs to do to handle notifications */
 
        printf("Hello from vcore_entry in vcore %d with temp addr %p and temp %p\n",
index c0d4ee5..f240133 100644 (file)
@@ -104,21 +104,16 @@ void vcore_entry(void)
 
 /* begin: stuff userspace needs to do to handle notifications */
 
-       struct vcore *vc = &__procinfo.vcoremap[vcoreid];
        struct preempt_data *vcpd;
        vcpd = &__procdata.vcore_preempt_data[vcoreid];
        
+       /* checks if a preempt is pending, yields if so */
+       check_preempt_pending(vcoreid);
+               
        /* here is how you receive an event (remember to register the syscall
         * handler, and whatever other handlers you want). */
        handle_events(vcoreid);
 
-       /* how we tell a preemption is pending (regardless of notif/events) */
-       if (vc->preempt_pending) {
-               printf("Oh crap, vcore %d is being preempted!  Yielding\n", vcoreid);
-               sys_yield(TRUE);
-               printf("After yield on vcore %d. I wasn't being preempted.\n", vcoreid);
-       }
-               
        /* Restart vcore0's context. */
        if (vcoreid == 0) {
                vcpd->notif_pending = 0;
index 919e16e..ae16f8a 100644 (file)
@@ -158,13 +158,16 @@ unsigned int get_event_type(struct event_mbox *ev_mbox)
 handle_event_t ev_handlers[MAX_NR_EVENT] = {[EV_EVENT] handle_ev_ev, 0};
 
 /* Handle an mbox.  This is the receive-side processing of an event_queue.  It
- * takes an ev_mbox, since the vcpd mbox isn't a regular ev_q. */
+ * takes an ev_mbox, since the vcpd mbox isn't a regular ev_q.  For now, we
+ * check for preemptions between each event handler. */
 static int handle_mbox(struct event_mbox *ev_mbox, unsigned int flags)
 {
        struct event_msg local_msg;
        unsigned int ev_type;
        bool overflow = FALSE;
        int retval = 0;
+       uint32_t vcoreid = vcore_id();
+
        if (!event_activity(ev_mbox, flags))
                return retval;
        /* Try to dequeue, dispatch whatever you get.  TODO consider checking for
@@ -173,7 +176,7 @@ static int handle_mbox(struct event_mbox *ev_mbox, unsigned int flags)
                ev_type = local_msg.ev_type;
                if (ev_handlers[ev_type])
                        ev_handlers[ev_type](&local_msg, overflow);
-               /* TODO: check for preemption here */
+               check_preempt_pending(vcoreid);
                retval++;
        }
        /* Race here with another core clearing overflows/bits.  Don't have more
@@ -191,7 +194,7 @@ static int handle_mbox(struct event_mbox *ev_mbox, unsigned int flags)
                if (ev_handlers[bit])
                        ev_handlers[bit](0, overflow);
                retval++;
-               /* TODO: check for preemption here */
+               check_preempt_pending(vcoreid);
                /* Consider checking the queue for incoming messages while we're here */
        }
        BITMASK_FOREACH_SET(ev_mbox->ev_bitmap, MAX_NR_EVENT, bit_handler, TRUE);
index 78cae58..1cbfa87 100644 (file)
@@ -26,6 +26,12 @@ extern "C" {
 #define TRANSITION_STACK_PAGES 2
 #define TRANSITION_STACK_SIZE (TRANSITION_STACK_PAGES*PGSIZE)
 
+/* 2L-Scheduler operations.  Can be 0. */
+struct schedule_ops {
+       void (*preempt_pending)(void);
+};
+extern struct schedule_ops *sched_ops;
+
 /* Defined by glibc; Must be implemented by a user level threading library */
 extern void vcore_entry();
 
@@ -39,6 +45,7 @@ int vcore_request(size_t k);
 void vcore_yield(void);
 size_t max_vcores(void);
 size_t num_vcores(void);
+bool check_preempt_pending(uint32_t vcoreid);
 
 static inline void enable_notifs(uint32_t vcoreid)
 {
index dbff5dd..035203a 100644 (file)
 static size_t _max_vcores_ever_wanted = 1;
 static mcs_lock_t _vcore_lock = MCS_LOCK_INIT;
 
+/* Which operations we'll call for the 2LS.  Will change a bit with Lithe.  For
+ * now, there are no defaults. */
+struct schedule_ops default_2ls_ops = {0};
+struct schedule_ops *sched_ops = &default_2ls_ops;
+
 extern void** vcore_thread_control_blocks;
 
 /* Get a TLS, returns 0 on failure.  Vcores have their own TLS, and any thread
@@ -166,3 +171,20 @@ int vcore_id()
        return __vcoreid;
 }
 
+/* Deals with a pending preemption (checks, responds).  If the 2LS registered a
+ * function, it will get run.  Returns true if you got preempted.  Called
+ * 'check' instead of 'handle', since this isn't an event handler.  It's the "Oh
+ * shit a preempt is on its way ASAP". */
+bool check_preempt_pending(uint32_t vcoreid)
+{
+       bool retval = FALSE;
+       if (__procinfo.vcoremap[vcoreid].preempt_pending) {
+               retval = TRUE;
+               if (sched_ops->preempt_pending)
+                       sched_ops->preempt_pending();
+               /* this tries to yield, but will pop back up if this was a spurious
+                * preempt_pending. */
+               sys_yield(TRUE);
+       }
+       return retval;
+}
index 3480775..cd2cd44 100644 (file)
@@ -84,16 +84,12 @@ void __attribute__((noreturn)) vcore_entry()
        uint32_t vcoreid = vcore_id();
 
        struct preempt_data *vcpd = &__procdata.vcore_preempt_data[vcoreid];
-       struct vcore *vc = &__procinfo.vcoremap[vcoreid];
 
        /* Should always have notifications disabled when coming in here. */
        assert(vcpd->notif_enabled == FALSE);
 
-       /* Put this in the loop that deals with notifications.  It will return if
-        * there is no preempt pending. */ 
+       check_preempt_pending(vcoreid);
        handle_events(vcoreid);
-       if (vc->preempt_pending)
-               sys_yield(TRUE);
        // TODO: consider making this restart path work for restarting as well as
        // freshly starting
        if (current_thread) {