VCORE_APPRO sets the ev_mbox
authorBarret Rhoden <brho@cs.berkeley.edu>
Thu, 24 Feb 2011 22:48:03 +0000 (14:48 -0800)
committerKevin Klues <klueska@cs.berkeley.edu>
Thu, 3 Nov 2011 00:35:59 +0000 (17:35 -0700)
When the kernel is picking what the vcore ought to be, the kernel will
use the vcore's ev_mbox.  Needs to be this way, since the user doesn't
know which vcore the message is going to (which is the nature of
VCORE_APPRO).  If  want something that allows a message to go to an
ev_q's mbox, but the IPIs to get sent somewhere else, then use something
like Round-Robin.

Documentation/async_events.txt
kern/src/event.c
kern/src/monitor.c
tests/mhello.c
tests/msr_nice_while.c
user/parlib/event.c

index ffc148b..f678aff 100644 (file)
@@ -183,6 +183,9 @@ types of events where they want the kernel to send the event/IPI to the
 'appropriate' vcore.  For example, when sending a message about a preemption
 coming in, it makes sense for the kernel to send it to the vcore that is going
 to get preempted, but the application could choose to ignore the notification.
+When this flag is set, the kernel will also use the vcore's ev_mbox, ignoring
+the process's choice.  We can change this later, but it doesn't really make
+sense for a process to pick an mbox and also say VCORE_APPRO.
 
 There are also interfaces in the kernel to put a message in an ev_mbox
 regardless of the process's wishes (post_vcore_event()), and can send an IPI
index a39efc5..c84c3cf 100644 (file)
@@ -60,7 +60,7 @@ void send_event(struct proc *p, struct event_queue *ev_q, struct event_msg *msg,
 {
        struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
        struct proc *old_proc = pcpui->cur_proc;        /* uncounted ref */
-       struct event_mbox *ev_mbox, *vcore_mbox;
+       struct event_mbox *ev_mbox = 0, *vcore_mbox;
        struct event_msg local_msg = {0};
        assert(p);
        if (!ev_q) {
@@ -80,11 +80,15 @@ void send_event(struct proc *p, struct event_queue *ev_q, struct event_msg *msg,
                pcpui->cur_proc = p;
                lcr3(p->env_cr3);
        }
-       /* If we don't follow the kernel's advice, do what the process wants */
-       if (!(ev_q->ev_flags & EVENT_VCORE_APPRO))
+       /* Get the mbox and vcoreid */
+       /* 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(p, vcoreid);
+       } else {        /* common case */
+               ev_mbox = ev_q->ev_mbox;
                vcoreid = ev_q->ev_vcore;
-       /* Post the event.  Need to get the initial mbox (might be 0). */
-       ev_mbox = ev_q->ev_mbox;
+       }
        /* Check on the style, which could affect our mbox selection.  Other styles
         * would go here (or in similar functions we call to).  Important thing is
         * we come out knowing which vcore to send to in the event of an IPI, and we
@@ -99,13 +103,17 @@ void send_event(struct proc *p, struct event_queue *ev_q, struct event_msg *msg,
                        ev_mbox = get_proc_ev_mbox(p, vcoreid);
        }
        /* 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). */
+        * which vcore to send an IPI to (if we send one).  The mbox could be the
+        * vcore's vcpd ev_mbox. */
        if (!ev_mbox) {
                /* this is a process error */
                warn("[kernel] ought to have an mbox by now!");
                goto out;
        }
-       if (!is_user_rwaddr(ev_mbox)) {
+       vcore_mbox = get_proc_ev_mbox(p, vcoreid);
+       /* Allows the mbox to be the right vcoreid mbox (a KVA in procdata), or any
+        * other user RW location. */
+       if ((ev_mbox != vcore_mbox) && (!is_user_rwaddr(ev_mbox))) {
                /* Ought to kill them, just warn for now */
                warn("[kernel] Illegal addr for ev_mbox");
                goto out;
@@ -117,8 +125,7 @@ void send_event(struct proc *p, struct event_queue *ev_q, struct event_msg *msg,
        if (ev_q->ev_flags & EVENT_IPI) {
                /* if the mbox we sent to isn't the default one, we need to send the
                 * vcore an ev_q indirection event */
-               vcore_mbox = get_proc_ev_mbox(p, vcoreid);
-               if (!uva_is_kva(p, ev_mbox, vcore_mbox)) {
+               if ((ev_mbox != vcore_mbox) && (!uva_is_kva(p, ev_mbox, vcore_mbox))) {
                        /* it is tempting to send_kernel_event(), using the ev_q for that
                         * event, but that is inappropriate here, since we are sending to a
                         * specific vcore */
index 4ede378..83393a0 100644 (file)
@@ -549,6 +549,7 @@ int mon_measure(int argc, char *NTS *NT COUNT(argc) argv, trapframe_t *tf)
                        printk("No such proc\n");
                        return 1;
                }
+               printk("Careful: if this hangs, then the process isn't responding.\n");
                if (argc == 4) { /* single core being preempted-warned */
                        uint32_t pcoreid = strtol(argv[3], 0, 0);
                        spin_lock(&p->proc_lock);
index 00c982f..e2732ad 100644 (file)
@@ -53,6 +53,10 @@ int main(int argc, char** argv)
         * 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, TRUE);
+       /* 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;
+       register_kevent_q(ev_q, EV_PREEMPT_PENDING);
 
        /* Need to save this somewhere that you can find it again when restarting
         * core0 */
@@ -111,8 +115,12 @@ int main(int argc, char** argv)
 
 static void handle_generic(struct event_msg *ev_msg, bool overflow)
 {
-       printf("Got event type %d on vcore %d, with%s overflow\n", ev_msg->ev_type,
-              vcore_id(), overflow ? "" : "out");
+       if (ev_msg)
+               printf("Got event type %d on vcore %d, with%s overflow\n",
+                      ev_msg->ev_type, vcore_id(), overflow ? "" : "out");
+       else
+               printf("Got event type UNK on vcore %d, with%s overflow\n",
+                      vcore_id(), overflow ? "" : "out");
 }
 
 void vcore_entry(void)
index 21ef7f7..8ce6ad6 100644 (file)
@@ -22,8 +22,9 @@ int main(int argc, char** argv)
        /* set up to receive the PREEMPT_PENDING event.  EVENT_VCORE_APPRO tells the
         * kernel to send the msg to whichever vcore is appropriate.  Pthread code
         * will see the preemption and yield. */
-       enable_kevent(EV_PREEMPT_PENDING, 0,
-                     EVENT_IPI | EVENT_NOMSG | EVENT_VCORE_APPRO);
+       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);
 
        /* actually only need one less, since the _S will be pthread 0 */
        for (int i = 0; i < max_vcores() - 1; i++)
index ae16f8a..ced55f6 100644 (file)
@@ -174,6 +174,7 @@ static int handle_mbox(struct event_mbox *ev_mbox, unsigned int flags)
         * overflow first */
        while (!bcq_dequeue(&ev_mbox->ev_msgs, &local_msg, NR_BCQ_EVENTS)) {
                ev_type = local_msg.ev_type;
+               printd("BCQ: ev_type: %d\n", ev_type);
                if (ev_handlers[ev_type])
                        ev_handlers[ev_type](&local_msg, overflow);
                check_preempt_pending(vcoreid);
@@ -191,6 +192,7 @@ static int handle_mbox(struct event_mbox *ev_mbox, unsigned int flags)
         * thread safe (tested on some code in mhello, asm looks like it knows to
         * have the function use addresses relative to the frame pointer). */
        void bit_handler(unsigned int bit) {
+               printd("Bit: ev_type: %d\n", ev_type);
                if (ev_handlers[bit])
                        ev_handlers[bit](0, overflow);
                retval++;