Send preemption messages (XCC)
authorBarret Rhoden <brho@cs.berkeley.edu>
Wed, 12 Oct 2011 00:03:19 +0000 (17:03 -0700)
committerKevin Klues <klueska@cs.berkeley.edu>
Thu, 3 Nov 2011 00:36:08 +0000 (17:36 -0700)
When a vcore is preempted, the kernel will send an event to the
appropriate ev_q.  For all uthread code, the handler and ev_q is set up
in uthread_lib_init().  Note that the handler does nothing yet but give
us some helpful information.

Reinstall your kernel headers (event.h).

kern/include/ros/event.h
kern/src/process.c
tests/mhello.c
user/parlib/uthread.c

index 7736a85..2351dd8 100644 (file)
@@ -29,7 +29,7 @@
 #define EV_NONE                                         0
 #define EV_PREEMPT_PENDING              1
 #define EV_GANG_PREMPT_PENDING  2
-#define EV_VCORE_REVOKE                         3
+#define EV_VCORE_PREEMPT                3
 #define EV_GANG_RETURN                  4
 #define EV_USER_IPI                             5
 #define EV_PAGE_FAULT                   6
index 61e50d1..f440a20 100644 (file)
@@ -975,10 +975,14 @@ void __proc_preempt_warnall(struct proc *p, uint64_t when)
 void __proc_preempt_core(struct proc *p, uint32_t pcoreid)
 {
        uint32_t vcoreid = get_vcoreid(p, pcoreid);
-
+       struct event_msg preempt_msg = {0};
        p->procinfo->vcoremap[vcoreid].preempt_served = TRUE;
        // expects a pcorelist.  assumes pcore is mapped and running_m
        __proc_take_cores(p, &pcoreid, 1, __preempt, (long)p, 0, 0);
+       /* Send a message about the preemption. */
+       preempt_msg.ev_type = EV_VCORE_PREEMPT;
+       preempt_msg.ev_arg2 = vcoreid;
+       send_kernel_event(p, &preempt_msg, 0);
 }
 
 /* Raw function to preempt every vcore.  If you care about locking, do it before
@@ -992,6 +996,7 @@ void __proc_preempt_all(struct proc *p)
        TAILQ_FOREACH(vc_i, &p->online_vcs, list)
                vc_i->preempt_served = TRUE;
        __proc_take_allcores(p, __preempt, (long)p, 0, 0);
+       /* TODO: send a bulk preemption message */
 }
 
 /* Warns and preempts a vcore from p.  No delaying / alarming, or anything.  The
index dc9b4f0..7c80130 100644 (file)
@@ -68,6 +68,7 @@ int main(int argc, char** argv)
        struct event_queue *ev_q = get_event_q();
        ev_q->ev_flags = EVENT_IPI | EVENT_NOMSG | EVENT_VCORE_APPRO;
        register_kevent_q(ev_q, EV_PREEMPT_PENDING);
+       /* We also receive preemption events, it is set up in uthread.c */
 
        /* Inits a thread for us, though we won't use it.  Just a hack to get into
         * _M mode.  Note this requests one vcore for us */
@@ -97,9 +98,9 @@ int main(int argc, char** argv)
        msg.ev_type = 4;
        sys_self_notify(2, 4, &msg);
        udelay(5000000);
-       printf("Vcore 0 notifying itself with notif 3!\n");
-       msg.ev_type = 3;
-       sys_notify(sys_getpid(), 3, &msg);
+       printf("Vcore 0 notifying itself with notif 6!\n");
+       msg.ev_type = 6;
+       sys_notify(sys_getpid(), 6, &msg);
        udelay(1000000);
 
        /* test loop for restarting a notif_tf */
index 22222bd..eaf9d4c 100644 (file)
@@ -11,12 +11,16 @@ struct schedule_ops default_2ls_ops = {0};
 struct schedule_ops *sched_ops __attribute__((weak)) = &default_2ls_ops;
 
 __thread struct uthread *current_uthread = 0;
+/* ev_q for all preempt messages (handled here to keep 2LSs from worrying
+ * extensively about the details.  Will call out when necessary. */
+struct event_queue *preempt_ev_q;
 
 /* static helpers: */
 static int __uthread_allocate_tls(struct uthread *uthread);
 static int __uthread_reinit_tls(struct uthread *uthread);
 static void __uthread_free_tls(struct uthread *uthread);
 static void __run_current_uthread_raw(void);
+static void handle_vc_preempt(struct event_msg *ev_msg, unsigned int ev_type);
 
 /* The real 2LS calls this, passing in a uthread representing thread0.  When it
  * returns, you're in _M mode, still running thread0, on vcore0 */
@@ -49,6 +53,14 @@ int uthread_lib_init(struct uthread *uthread)
        /* don't forget to enable notifs on vcore0.  if you don't, the kernel will
         * restart your _S with notifs disabled, which is a path to confusion. */
        __enable_notifs(0);
+       /* Receive preemption events */
+       ev_handlers[EV_VCORE_PREEMPT] = handle_vc_preempt;
+       preempt_ev_q = get_big_event_q();
+       preempt_ev_q->ev_flags = EVENT_IPI | EVENT_INDIR | EVENT_FALLBACK |
+                                EVENT_NOTHROTTLE | EVENT_VCORE_MUST_RUN;
+       register_kevent_q(preempt_ev_q, EV_VCORE_PREEMPT);
+       printd("[user] registered %08p (flags %08p) for preempt messages\n",
+              preempt_ev_q, preempt_ev_q->ev_flags);
        /* Get ourselves into _M mode.  Could consider doing this elsewhere... */
        while (!in_multi_mode()) {
                vcore_request(1);
@@ -357,6 +369,11 @@ void uth_enable_notifs(void)
        }
 }
 
+static void handle_vc_preempt(struct event_msg *ev_msg, unsigned int ev_type)
+{
+       printf("Vcore %d was preempted, we're fucked!!!\n", ev_msg->ev_arg2);
+}
+
 /* Attempts to register ev_q with sysc, so long as sysc is not done/progress.
  * Returns true if it succeeded, and false otherwise.  False means that the
  * syscall is done, and does not need an event set (and should be handled