Public VCPD mboxes (XCC)
authorBarret Rhoden <brho@cs.berkeley.edu>
Mon, 5 Dec 2011 23:32:58 +0000 (15:32 -0800)
committerBarret Rhoden <brho@cs.berkeley.edu>
Thu, 15 Dec 2011 22:48:41 +0000 (14:48 -0800)
Each vcore has two mboxes, one for public messages (meaning they can be
read by any vcore) and one for private (specific to that vcore only).
Both are checked by handle_events().  We need this because there are
situations where we will need to read another vcores messages
(preemption recovery) to make sure we get certain messages
(specifically, INDIRs and preemption notices) regardless of preemption,
yielding, etc.

Check the Documentation for more info.  We don't use these yet for much
(there's no ev_q flag, for instance), and preemptions still use INDIRs.
That'll change shortly.

Reinstall your kernel headers.

14 files changed:
Documentation/async_events.txt
kern/include/event.h
kern/include/ros/event.h
kern/src/event.c
kern/src/monitor.c
kern/src/syscall.c
tests/eth_audio.c
tests/mhello.c
tests/msr_dumb_while.c
user/c3po/threads/vcore.c
user/parlib/event.c
user/parlib/include/event.h
user/parlib/vcore.c
user/pthread/pthread.c

index 5fa6bd6..7678afc 100644 (file)
@@ -62,6 +62,13 @@ all things related to the management of vcores, such as its event_mbox (queue
 of incoming messages/notifications/events).  Both the kernel and the vcore
 code know to look here for a variety of things.
 
+Vcore-business: This is a term I use for a class of messages where the receiver
+is the actual vcore, and not just using the vcore as a place to receive the
+message.  Examples of vcore-business are INDIR events, preempt_pending events,
+scheduling events (self-ipis by the 2LS from one vcore to another), and things
+like that.  There are two types: public and private.  Private will only be
+handled by that vcore.  Public might be handled by another vcore.
+
 Notif_table: This is a list of event_q*s that correspond to certain
 unexpected/"one-sided" events the kernel sends to the process.  It is similar
 to an IRQ table in the kernel.  Each event_q tells the kernel how the process
@@ -85,6 +92,10 @@ other either (in the event of weirdness, the producers give up and say the
 buffer is full).  This means that a process can produce for one of its ev_qs
 (which is what they need to do to send message to itself).
 
+UCQ: "unbounded concurrent queue".  This is a data structure allowing the kernel
+to produce an unbounded number of messages for the process to consume.  The main
+limitation to the number of messages is RAM.  Check out its documentation.
+
 2. Async Syscalls and I/O
 ====================
 2.1 Basics
@@ -352,10 +363,24 @@ poll its own ev_q, so you won't need the indirection event.
 
 Additionally, note that IPIs and INDIRs can be spurious.  It's not a big deal to
 receive and IPI and have nothing to do, or to be told to check an empty ev_q.
-All of the event handling code can deal with this.  The only thing you shouldn't
-do is have one vcore handle another's VCPD.  That mbox is meant for
-vcore-business.  Never use a VCPD for messages you might want to receive if that
-vcore is offline.
+All of the event handling code can deal with this.
+
+INDIR events are sent to the VCPD public mbox, which means they will get handled
+if the vcore gets preempted.  Any other messages sent here will also get handled
+during a preemption.  However, the only type of messages you should use this for
+are ones that can handle spurious messages.  The completion of a syscall is an
+example of a message that cannot be spurious.  Since INDIRs can be spurious, we
+can use the public mbox.  (Side note: the kernel may spam INDIRs in attempting
+to make sure you get the message on a vcore that didn't yield.)
+
+Never use a VCPD mbox (public or private) for messages you might want to receive
+if that vcore is offline.  If you want to be sure to get a message, create your
+own ev_q and set flags for INDIR, FALLBACK, and IPI.  There's no guarantee a
+*specific* message will get looked at.  In cases where it won't, the kernel will
+send that message to another vcore.  For example, if the kernel posts an INDIR
+to a VCPD mbox (the public one btw) and it loses a race with the vcore yielding,
+the vcore might never see that message.  However, the kernel knows it lost the
+race, and will find another vcore to send it to.
 
 3.3.2: Fallback
 ---------------
@@ -428,21 +453,7 @@ this can be a bit tricky if you have multiple places pointing to the same ev_q
 3.3.3: Fallback and Preemption
 ---------------
 FALLBACK doesn't protect you from preemptions.  A vcore can be preempted and
-have INDIRs in its VCPD.  Dealing with this is part of the 2LSs job.  The 2LS
-must check the ev_mboxes/ev_qs of all ev_qs that could send INDIRS to the
-offline vcore.  There could be INDIRS in the VCPD that are just lying there.
-The 2LS knows which ev_qs these are (such as for completed syscalls), and for
-many things, this will be a common ev_q (such as for 'vcore-x-was-preempted').
-
-A couple things will ameliorate this:
-1) the 2LS can inspect the VCPD of the target.  If it is empty, then we don't
-have to worry about any INDIRs, and we're done worrying about their messages
-(though we still have to worry about them being stuck in vcore context and
-having a uthread).  Also note you only need to check the UCQ, since INDIRs must
-be messages, not bits.
-2) the kernel could initiate FALLBACK if the vcore has a preempt pending, which
-ought to cut down on this happening frequently. (we don't do this yet, and
-probably never will, since it complicates the design).
+have INDIRs in its VCPD.
 
 It is tempting to just use sys_change_vcore(), which will change the calling
 vcore to the new one.  This should only be used to "unstick" a vcore.  A vcore
@@ -463,6 +474,20 @@ sys_change_vcore().  We want the new vcore to know the old vcore was put
 offline: a preemption (albeit one that it chose to do, and one that isn't stuck
 in vcore context).
 
+One older way to deal with this was to force the 2LS to deal with this. The 2LS
+would check the ev_mboxes/ev_qs of all ev_qs that could send INDIRS to the
+offline vcore.  There could be INDIRS in the VCPD that are just lying there.
+The 2LS knows which ev_qs these are (such as for completed syscalls), and for
+many things, this will be a common ev_q (such as for 'vcore-x-was-preempted').
+However, this is a huge pain in the ass, since a preempted vcore could have the
+FALLBACK INDIR for an ev_q associated with another vcore.  To deal with this,
+the 2LS would need to check *every* ev_q that requests INDIRs.  We don't do
+this.
+
+Instead, we simply have the remote core check the VCPD public mbox of the
+preempted vcore.  INDIRs (and other vcore business that other vcores can handle)
+will get sorted here.
+
 3.3.5: Lists to Find Vcores
 ---------------
 A process has three lists: online, bulk_preempt, and inactive.  These not only
@@ -476,6 +501,37 @@ restart when it tries to yield.  And this all works without locking the
 proc_lock.  There are a bunch more details and races avoided.  Check the code
 out.
 
+3.3.6: Vcore Business and the VCPD mboxs
+---------------
+There are two types of VCPD mboxes: public and private.  Public ones will get
+handled during preemption recovery.  Messages sent here need to be handle-able
+by any vcore.  Private messages are for that specific vcore.  In the common
+case, the public mbox will usually only get looked at by its vcore.  Only during
+recovery and some corner cases will we deal with it remotely.
+
+Here's some guidelines: if you message is spammy and the handler can deal with
+spurious events and it doesn't need to be on a specific vcore, then go with
+public.  Examples of public mbox events are ones that need to be spammed:
+preemption recovery, INDIRs, etc.  Note that you won't need to worry about
+these: uthread code and the kernel handle them.  But if you have something
+similar, then that's where it would go.  You can also send non-spammy things,
+but there's no guarantee they'll be looked at.
+
+Some messages should only be sent to the private mbox.  These include ones that
+make no sense for other vcores to handle.  Examples: 2LS IPIs/preemptions (like
+"change your scheduling policy vcore 3", preemption-pending notifs from the
+kernel, timer interrupts, etc.
+
+An example of something that shouldn't be sent to either is syscall completions.
+They can't be spammed, so you can't send them around like INDIRs.  And they need
+to be dealt with.  Other than carefully-spammed public messages, there's no
+guarantee of getting a message for certain scenarios (yields).  Instead, use an
+ev_q with INDIR set.
+
+Also note that a 2LS could set up a big ev_q with EVENT_IPI and not EVENT_INDIR,
+and then poll for that in their vcore_entry().  This is equivalent to setting up
+a small ev_q with EVENT_IPI and pointing it at the private mbox.
+
 3.4 Application-specific Event Handling
 ---------------------------------------
 So what happens when the vcore/2LS isn't handling an event queue, but has been
@@ -618,7 +674,9 @@ are issues with preemption recovery if you do.  In short, if two uthreads are
 both DONT_MIGRATE with notifs enabled on two different vcores, and one vcore
 gets preempted while the other gets an IPI telling it to recover the other one,
 both could keep bouncing back and forth if they handle their preemption
-*messages* without dealing with their own DONT_MIGRATEs first.
+*messages* without dealing with their own DONT_MIGRATEs first.  Note that the
+preemption recovery code can handle having a DONT_MIGRATE thread on the vcore.
+This is a special case, and it is very careful about how cur_uthread works.
 
 All uses of DONT_MIGRATE must reenable notifs (and check messages) at some
 point.  One such case is uthread_yield().  Another is mcs_unlock_notifsafe().
index fae1d95..471f279 100644 (file)
@@ -14,6 +14,7 @@
 void send_event(struct proc *p, struct event_queue *ev_q, struct event_msg *msg,
                 uint32_t vcoreid);
 void send_kernel_event(struct proc *p, struct event_msg *msg, uint32_t vcoreid);
-void post_vcore_event(struct proc *p, struct event_msg *msg, uint32_t vcoreid);
+void post_vcore_event(struct proc *p, struct event_msg *msg, uint32_t vcoreid,
+                      int ev_flags);
 
 #endif /* ROS_KERN_EVENT_H */
index 6ee295b..4a87960 100644 (file)
 #define EVENT_INDIR                            0x002   /* send an indirection event to vcore */
 #define EVENT_FALLBACK                 0x004   /* pick another vcore if it's offline */
 #define EVENT_NOMSG                            0x008   /* just send the bit, not the msg */
-#define EVENT_ROUNDROBIN               0x010   /* pick a vcore, RR style */
-#define EVENT_VCORE_APPRO              0x020   /* send to where the kernel wants */
-#define EVENT_NOTHROTTLE               0x040   /* send all alerts (no throttling) */
-#define EVENT_VCORE_MUST_RUN   0x080   /* Alerts go to a vcore that will run */
+#define EVENT_NOTHROTTLE               0x010   /* send all alerts (no throttling) */
+#define EVENT_VCORE_MUST_RUN   0x020   /* Alerts go to a vcore that will run */
+/* Not seriously used flags */
+#define EVENT_ROUNDROBIN               0x040   /* pick a vcore, RR style */
+#define EVENT_VCORE_APPRO              0x080   /* send to where the kernel wants */
+#define EVENT_VCORE_PRIVATE            0x100   /* Will go to the private VCPD mbox */
+
 /* Flags from the program to the 2LS */
-#define EVENT_JUSTHANDLEIT             0x100   /* 2LS should handle the ev_q */
-#define EVENT_THREAD                   0x200   /* spawn thread to handle ev_q */
+#define EVENT_JUSTHANDLEIT             0x200   /* 2LS should handle the ev_q */
+#define EVENT_THREAD                   0x400   /* spawn thread to handle ev_q */
 
 /* Event Message Types */
 #define EV_NONE                                         0
@@ -102,7 +105,8 @@ struct preempt_data {
        bool                                            notif_disabled;         /* vcore unwilling to recv*/
        bool                                            notif_pending;          /* notif k_msg on the way */
        bool                                            can_rcv_msg;            /* can receive FALLBACK */
-       struct event_mbox                       ev_mbox;
+       struct event_mbox                       ev_mbox_public;         /* can be read remotely */
+       struct event_mbox                       ev_mbox_private;        /* for this vcore only */
 };
 
 #endif /* ROS_INC_EVENT_H */
index e5641ab..f2eaa27 100644 (file)
 #include <assert.h>
 #include <pmap.h>
 
-/* Note this returns the user address of the mbox, not the KVA.  You'll need
- * current loaded to access this, and it will work for any process. */
-static struct event_mbox *get_proc_ev_mbox(uint32_t vcoreid)
+/* Note these three helpers return the user address of the mbox, not the KVA.
+ * Load current to access this, and it will work for any process. */
+static struct event_mbox *get_vcpd_mbox_priv(uint32_t vcoreid)
 {
-       return &__procdata.vcore_preempt_data[vcoreid].ev_mbox;
+       return &__procdata.vcore_preempt_data[vcoreid].ev_mbox_private;
+}
+
+static struct event_mbox *get_vcpd_mbox_pub(uint32_t vcoreid)
+{
+       return &__procdata.vcore_preempt_data[vcoreid].ev_mbox_public;
+}
+
+static struct event_mbox *get_vcpd_mbox(uint32_t vcoreid, int ev_flags)
+{
+       if (ev_flags & EVENT_VCORE_PRIVATE)
+               return get_vcpd_mbox_priv(vcoreid);
+       else
+               return get_vcpd_mbox_pub(vcoreid);
 }
 
 /* Posts a message to the mbox, subject to flags.  Feel free to send 0 for the
@@ -67,7 +80,7 @@ static void send_indir_to_vcore(struct event_queue *ev_q, uint32_t vcoreid)
        struct event_msg local_msg = {0};
        local_msg.ev_type = EV_EVENT;
        local_msg.ev_arg3 = ev_q;
-       post_ev_msg(get_proc_ev_mbox(vcoreid), &local_msg, 0);
+       post_ev_msg(get_vcpd_mbox_pub(vcoreid), &local_msg, 0);
        /* Set notif pending, so userspace doesn't miss the INDIR while yielding */
        wmb(); /* Ensure ev_msg write is before notif_pending */
        vcpd->notif_pending = TRUE;
@@ -324,7 +337,8 @@ void send_event(struct proc *p, struct event_queue *ev_q, struct event_msg *msg,
        /* If we're going with APPRO, we use the kernel's suggested vcore's ev_mbox.
         * vcoreid is already what the kernel suggests. */
        if (ev_q->ev_flags & EVENT_VCORE_APPRO) {
-               ev_mbox = get_proc_ev_mbox(vcoreid);
+               /* flags determine if it's private (like a preempt pending) or not */
+               ev_mbox = get_vcpd_mbox(vcoreid, ev_q->ev_flags);
        } else {        /* common case */
                ev_mbox = ev_q->ev_mbox;
                vcoreid = ev_q->ev_vcore;
@@ -344,7 +358,7 @@ void send_event(struct proc *p, struct event_queue *ev_q, struct event_msg *msg,
                 * RR probably are non-vcore-business, and thus inappropriate for a VCPD
                 * ev_mbox. */
                if (!ev_mbox)
-                       ev_mbox = get_proc_ev_mbox(vcoreid);
+                       ev_mbox = get_vcpd_mbox(vcoreid, ev_q->ev_flags);
        }
        /* At this point, we ought to have the right mbox to send the msg to, and
         * which vcore to send an IPI to (if we send one).  The mbox could be the
@@ -367,7 +381,7 @@ void send_event(struct proc *p, struct event_queue *ev_q, struct event_msg *msg,
        post_ev_msg(ev_mbox, msg, ev_q->ev_flags);
        wmb();  /* ensure ev_msg write is before alert_vcore() */
        /* Help out userspace a bit by checking for a potentially confusing bug */
-       if ((ev_mbox == get_proc_ev_mbox(vcoreid)) &&
+       if ((ev_mbox == get_vcpd_mbox_pub(vcoreid)) &&
            (ev_q->ev_flags & EVENT_INDIR))
                printk("[kernel] User-bug: ev_q has an INDIR with a VCPD ev_mbox!\n");
        /* Prod/alert a vcore with an IPI or INDIR, if desired */
@@ -392,15 +406,22 @@ void send_kernel_event(struct proc *p, struct event_msg *msg, uint32_t vcoreid)
                send_event(p, ev_q, msg, vcoreid);
 }
 
-/* Writes the msg to the vcpd/default mbox of the vcore.  Needs to load current,
- * but doesn't need to care about what the process wants.  Note this isn't
- * commonly used - just the monitor and sys_self_notify(). */
-void post_vcore_event(struct proc *p, struct event_msg *msg, uint32_t vcoreid)
+/* Writes the msg to the vcpd mbox of the vcore.  If you want the private mbox,
+ * send in the ev_flag EVENT_VCORE_PRIVATE.  If not, the message could
+ * be received by other vcores if the given vcore is offline/preempted/etc.
+ * Whatever other flags you pass in will get sent to post_ev_msg.  Currently,
+ * the only one that will get looked at is NO_MSG (set a bit).
+ *
+ * This needs to load current (switch_to), but doesn't need to care about what
+ * the process wants.  Note this isn't commonly used - just the monitor and
+ * sys_self_notify(). */
+void post_vcore_event(struct proc *p, struct event_msg *msg, uint32_t vcoreid,
+                      int ev_flags)
 {
        /* Need to set p as current to post the event */
        struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
        struct proc *old_proc = switch_to(p);
        /* *ev_mbox is the user address of the vcpd mbox */
-       post_ev_msg(get_proc_ev_mbox(vcoreid), msg, 0); /* no chance for a NOMSG */
+       post_ev_msg(get_vcpd_mbox(vcoreid, ev_flags), msg, ev_flags);
        switch_back(p, old_proc);
 }
index ea6fd8b..9a2f637 100644 (file)
@@ -458,7 +458,8 @@ int mon_notify(int argc, char *NTS *NT COUNT(argc) argv, trapframe_t *tf)
        msg.ev_type = strtol(argv[2], 0, 0);
        if (argc == 4) {
                vcoreid = strtol(argv[3], 0, 0);
-               post_vcore_event(p, &msg, vcoreid);
+               /* This will go to the private mbox */
+               post_vcore_event(p, &msg, vcoreid, EVENT_VCORE_PRIVATE);
                proc_notify(p, vcoreid);
        } else {
                /* o/w, try and do what they want */
index 1060c2a..317ac8c 100644 (file)
@@ -375,7 +375,7 @@ static int sys_proc_yield(struct proc *p, bool being_nice)
 }
 
 static void sys_change_vcore(struct proc *p, uint32_t vcoreid,
-                            bool enable_my_notif)
+                             bool enable_my_notif)
 {
        struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
        /* Change to vcore may start the vcore up remotely before we can finish the
@@ -384,7 +384,7 @@ static void sys_change_vcore(struct proc *p, uint32_t vcoreid,
        finish_sysc(pcpui->cur_sysc, pcpui->cur_proc);
        pcpui->cur_sysc = 0;    /* don't touch sysc again */
        proc_change_to_vcore(p, vcoreid, enable_my_notif);
-       /* Should't return, to prevent the chance of mucking with cur_sysc.
+       /* Shouldn't return, to prevent the chance of mucking with cur_sysc.
         * smp_idle will make sure we run the appropriate cur_tf (which will be the
         * new vcore for successful calls). */
        smp_idle();
@@ -726,7 +726,7 @@ static int sys_self_notify(struct proc *p, uint32_t vcoreid,
                }
        }
        /* this will post a message and IPI, regardless of wants/needs/debutantes.*/
-       post_vcore_event(p, &local_msg, vcoreid);
+       post_vcore_event(p, &local_msg, vcoreid, EVENT_VCORE_PRIVATE);
        proc_notify(p, vcoreid);
        return 0;
 }
index 8eec163..6ce01c9 100644 (file)
@@ -102,7 +102,7 @@ void vcore_entry(void)
        vcpd = &__procdata.vcore_preempt_data[vcoreid];
        
        /* Ghetto way to get just an event number */
-       unsigned int ev_type = get_event_type(&vcpd->ev_mbox);
+       unsigned int ev_type = get_event_type(&vcpd->ev_mbox_public);
 
        /* ETHAUD app: process the packet if we got a notif */
        if (ev_type == EV_FREE_APPLE_PIE)
index ff82411..03babf4 100644 (file)
@@ -63,7 +63,7 @@ int main(int argc, char** argv)
         * event and IPI for USER_IPIs on vcore 0.  Check event.c for more stuff.
         * Note you don't have to register for USER_IPIs to receive ones you send
         * yourself with sys_self_notify(). */
-       enable_kevent(EV_USER_IPI, 0, EVENT_IPI);
+       enable_kevent(EV_USER_IPI, 0, EVENT_IPI | EVENT_VCORE_PRIVATE);
        /* Receive pending preemption events.  Can also get a MSG if you want. */
        struct event_queue *ev_q = get_event_q();
        ev_q->ev_flags = EVENT_IPI | EVENT_NOMSG | EVENT_VCORE_APPRO;
index 16a58cd..0f965b5 100644 (file)
@@ -12,7 +12,7 @@
 int main(int argc, char** argv)
 {
        /* Get EV_ALARM on vcore 1, with IPI. */
-       enable_kevent(EV_ALARM, 1, EVENT_IPI);
+       enable_kevent(EV_ALARM, 1, EVENT_IPI | EVENT_VCORE_PRIVATE);
 
        vcore_request(max_vcores());
 
@@ -25,7 +25,7 @@ void vcore_entry(void)
        struct preempt_data *vcpd = &__procdata.vcore_preempt_data[0];
        vcpd->notif_disabled = FALSE;
 
-       unsigned int ev_type = get_event_type(&vcpd->ev_mbox);
+       unsigned int ev_type = get_event_type(&vcpd->ev_mbox_private);
        if (ev_type == EV_ALARM)
                printf("[T]:009:E:%llu\n", read_tsc());
        while(1);
index f79f174..65bb95b 100644 (file)
@@ -75,10 +75,10 @@ void vcore_startup()
        /* Tell the kernel where and how we want to receive events.  This is just an
         * example of what to do to have a notification turned on.  We're turning on
         * USER_IPIs, posting events to vcore 0's vcpd, and telling the kernel to
-        * send to vcore 0.  Note sys_self_notify will ignore the vcoreid pref.
-        * Also note that enable_kevent() is just an example, and you probably want
-        * to use parts of event.c to do what you want. */
-       enable_kevent(EV_USER_IPI, 0, EVENT_IPI);
+        * send to vcore 0.  Note sys_self_notify will ignore the vcoreid and
+        * private preference.  Also note that enable_kevent() is just an example,
+        * and you probably want to use parts of event.c to do what you want. */
+       enable_kevent(EV_USER_IPI, 0, EVENT_IPI | EVENT_VCORE_PRIVATE);
 
        /* Grab a reference to the main_thread on the current stack (i.e.
         * current_thread, since we know this has been set up for us properly by
index 0bd6b11..eb5712c 100644 (file)
@@ -73,11 +73,16 @@ struct event_queue *get_event_q(void)
        return ev_q;
 }
 
-/* Gets a small ev_q, with ev_mbox pointing to the vcpd mbox of vcoreid */
-struct event_queue *get_event_q_vcpd(uint32_t vcoreid)
+/* Gets a small ev_q, with ev_mbox pointing to the vcpd mbox of vcoreid.  If
+ * ev_flags has EVENT_VCORE_PRIVATE set, it'll give you the private mbox.  o/w,
+ * you'll get the public one. */
+struct event_queue *get_event_q_vcpd(uint32_t vcoreid, int ev_flags)
 {
        struct event_queue *ev_q = get_event_q();
-       ev_q->ev_mbox = &__procdata.vcore_preempt_data[vcoreid].ev_mbox;
+       if (ev_flags & EVENT_VCORE_PRIVATE)
+               ev_q->ev_mbox = &vcpd_of(vcoreid)->ev_mbox_private;
+       else
+               ev_q->ev_mbox = &vcpd_of(vcoreid)->ev_mbox_public;
        return ev_q;
 }
 
@@ -104,12 +109,15 @@ struct event_queue *clear_kevent_q(unsigned int ev_type)
 }
 
 /* Enables an IPI/event combo for ev_type sent to vcoreid's default mbox.  IPI
- * if you want one or not.  This is the simplest thing applications may want,
- * and shows how you can put the other event functions together to get similar
- * things done. */
+ * if you want one or not.  If you want the event to go to the vcore private
+ * mbox (meaning no other core should ever handle it), send in
+ * EVENT_VCORE_PRIVATE with ev_flags.
+ *
+ * This is the simplest thing applications may want, and shows how you can put
+ * the other event functions together to get similar things done. */
 void enable_kevent(unsigned int ev_type, uint32_t vcoreid, int ev_flags)
 {
-       struct event_queue *ev_q = get_event_q_vcpd(vcoreid);
+       struct event_queue *ev_q = get_event_q_vcpd(vcoreid, ev_flags);
        ev_q->ev_flags = ev_flags;
        ev_q->ev_vcore = vcoreid;
        ev_q->ev_handler = 0;
@@ -179,7 +187,7 @@ int handle_mbox_msgs(struct event_mbox *ev_mbox)
 /* 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.  For now, we
  * check for preemptions between each event handler. */
-static int handle_mbox(struct event_mbox *ev_mbox, unsigned int flags)
+int handle_mbox(struct event_mbox *ev_mbox, unsigned int flags)
 {
        int retval = 0;
        uint32_t vcoreid = vcore_id();
@@ -232,11 +240,14 @@ void handle_ev_ev(struct event_msg *ev_msg, unsigned int ev_type)
  * number of events handled. */
 int handle_events(uint32_t vcoreid)
 {
-       struct preempt_data *vcpd = &__procdata.vcore_preempt_data[vcoreid];
+       struct preempt_data *vcpd = vcpd_of(vcoreid);
+       int retval = 0;
        /* TODO: EVENT_NOMSG checks could be painful.  we could either keep track of
         * 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);
+       retval += handle_mbox(&vcpd->ev_mbox_private, EVENT_NOMSG);
+       retval += handle_mbox(&vcpd->ev_mbox_public, EVENT_NOMSG);
+       return retval;
 }
 
 /* Handles the events on ev_q IAW the event_handlers[].  If the ev_q is
index ff5b40c..f142c94 100644 (file)
@@ -17,7 +17,7 @@ struct event_queue *get_big_event_q(void);
 void put_big_event_q_raw(struct event_queue *ev_q);
 void put_big_event_q(struct event_queue *ev_q);
 struct event_queue *get_event_q(void);
-struct event_queue *get_event_q_vcpd(uint32_t vcoreid);
+struct event_queue *get_event_q_vcpd(uint32_t vcoreid, int ev_flags);
 void put_event_q(struct event_queue *ev_q);
 void register_kevent_q(struct event_queue *ev_q, unsigned int ev_type);
 struct event_queue *clear_kevent_q(unsigned int ev_type);
@@ -34,6 +34,7 @@ extern handle_event_t ev_handlers[];
 void handle_ev_ev(struct event_msg *ev_msg, unsigned int ev_type);
 int handle_events(uint32_t vcoreid);
 void handle_event_q(struct event_queue *ev_q);
+int handle_mbox(struct event_mbox *ev_mbox, unsigned int flags);
 int handle_mbox_msgs(struct event_mbox *ev_mbox);
 
 #endif /* _EVENT_H */
index 2ae69ec..d699746 100644 (file)
@@ -130,8 +130,8 @@ int vcore_init()
        if(allocate_transition_stack(0) || allocate_transition_tls(0))
                goto vcore_init_tls_fail;
 
-       /* Initialize our VCPD event queues' ucqs, two pages per vcore */
-       mmap_block = (uintptr_t)mmap(0, PGSIZE * 2 * max_vcores(),
+       /* Initialize our VCPD event queues' ucqs, two pages per ucq, 4 per vcore */
+       mmap_block = (uintptr_t)mmap(0, PGSIZE * 4 * max_vcores(),
                                     PROT_WRITE | PROT_READ,
                                     MAP_POPULATE | MAP_ANONYMOUS, -1, 0);
        /* Yeah, this doesn't fit in the error-handling scheme, but this whole
@@ -141,10 +141,13 @@ int vcore_init()
        /* Note we may end up doing vcore 0's elsewhere, for _Ss, or else have a
         * separate ev_q for that. */
        for (int i = 0; i < max_vcores(); i++) {
-               /* two pages each from the big block */
-               ucq_init_raw(&__procdata.vcore_preempt_data[i].ev_mbox.ev_msgs,
-                            mmap_block + (2 * i    ) * PGSIZE, 
-                            mmap_block + (2 * i + 1) * PGSIZE); 
+               /* four pages total for both ucqs from the big block (2 pages each) */
+               ucq_init_raw(&vcpd_of(i)->ev_mbox_public.ev_msgs,
+                            mmap_block + (4 * i    ) * PGSIZE,
+                            mmap_block + (4 * i + 1) * PGSIZE);
+               ucq_init_raw(&vcpd_of(i)->ev_mbox_private.ev_msgs,
+                            mmap_block + (4 * i + 2) * PGSIZE,
+                            mmap_block + (4 * i + 3) * PGSIZE);
        }
        atomic_init(&vc_req_being_handled, 0);
        assert(!in_vcore_context());
index 1ac33f9..cbb2105 100644 (file)
@@ -350,10 +350,10 @@ static int pthread_lib_init(void)
        /* Tell the kernel where and how we want to receive events.  This is just an
         * example of what to do to have a notification turned on.  We're turning on
         * USER_IPIs, posting events to vcore 0's vcpd, and telling the kernel to
-        * send to vcore 0.  Note sys_self_notify will ignore the vcoreid pref.
-        * Also note that enable_kevent() is just an example, and you probably want
-        * to use parts of event.c to do what you want. */
-       enable_kevent(EV_USER_IPI, 0, EVENT_IPI);
+        * send to vcore 0.  Note sys_self_notify will ignore the vcoreid and
+        * private preference.  Also note that enable_kevent() is just an example,
+        * and you probably want to use parts of event.c to do what you want. */
+       enable_kevent(EV_USER_IPI, 0, EVENT_IPI | EVENT_VCORE_PRIVATE);
 
        /* Handle syscall events. */
        ev_handlers[EV_SYSCALL] = pth_handle_syscall;