Differentiate between EVENT_SPAM* and wakeup (XCC)
authorBarret Rhoden <brho@cs.berkeley.edu>
Tue, 4 Aug 2015 21:14:23 +0000 (17:14 -0400)
committerBarret Rhoden <brho@cs.berkeley.edu>
Mon, 28 Sep 2015 19:14:00 +0000 (15:14 -0400)
Spamming is getting the message to some vcore that is guaranteed to
eventually receive the message (in a VCPD mbox).  Previously, this also
implied waking up the process.

This is slightly problematic, since spamming is tied to the VCPD mboxes.
If you want to wake up, you had to involve a VCPD mbox.  It ties the
wakeup to a *specific type* of mbox - in this case, the VCPD is a UCQ.
In the future, I'd like other mbox types, such as the "bitmap" type used
by the __ros_scp_simple_evq.

This commit splits the wakeup functionality into a new flag:
EVENT_WAKEUP.  Conceptually, it might be easier to follow the code this
way too.  Want a wakeup (from WAITING)?  Use EVENT_WAKEUP.

Almost all use cases that use some form of SPAM (public message or
indir) will also want a wakeup.  Maybe someone wants to be sure to hear
about something (spammed message), but don't care enough to wake up -
sort of a "if I happen to be running, I need to know FOO".

It's more plausible that an MCP could want a wakeup without the spam.
You could have a process-wide ev_q that was polled in a 2LS sched_entry.
There's no need for a spammed INDIR in this case.

Reinstall your kernel headers.

kern/include/ros/event.h
kern/src/event.c
tests/alarm.c
user/benchutil/alarm.c
user/parlib/signal.c
user/parlib/uthread.c
user/pthread/pthread.c

index d34a44d..85db296 100644 (file)
 /* #include <ros/ucq.h> included below */
 
 /* Event Delivery Flags from the process to the kernel */
-#define EVENT_IPI                              0x001   /* IPI the vcore (usually with INDIR) */
-#define EVENT_NOMSG                            0x002   /* just send the bit, not the msg */
-#define EVENT_SPAM_PUBLIC              0x004   /* spam the msg to public vcpd mboxes */
-#define EVENT_INDIR                            0x008   /* send an indirection event to vcore */
-#define EVENT_VCORE_PRIVATE            0x010   /* Will go to the private VCPD mbox */
-/* Delivery style flags */
-#define EVENT_SPAM_INDIR               0x020   /* spam INDIRs if the vcore's offline */
-#define EVENT_VCORE_MUST_RUN   0x040   /* Alerts go to a vcore that will run */
-#define EVENT_NOTHROTTLE               0x080   /* send all INDIRs (no throttling) */
-/* Not seriously used flags */
-#define EVENT_ROUNDROBIN               0x100   /* pick a vcore, RR style */
-#define EVENT_VCORE_APPRO              0x200   /* send to where the kernel wants */
+#define EVENT_IPI                              0x00001 /* IPI the vcore (usually with INDIR) */
+#define EVENT_NOMSG                            0x00002 /* just send the bit, not the msg */
+#define EVENT_SPAM_PUBLIC              0x00004 /* spam the msg to public vcpd mboxes */
+#define EVENT_INDIR                            0x00008 /* send an indirection event to vcore */
+#define EVENT_VCORE_PRIVATE            0x00010 /* Will go to the private VCPD mbox */
+#define EVENT_SPAM_INDIR               0x00020 /* spam INDIRs if the vcore's offline */
+#define EVENT_VCORE_MUST_RUN   0x00040 /* spams go to a vcore that will run */
+#define EVENT_NOTHROTTLE               0x00080 /* send all INDIRs (no throttling) */
+#define EVENT_ROUNDROBIN               0x00100 /* pick a vcore, RR style */
+#define EVENT_VCORE_APPRO              0x00200 /* send to where the kernel wants */
+#define EVENT_WAKEUP                   0x00400 /* wake up the process after sending */
 
 /* Flags from the program to the 2LS */
-#define EVENT_JUSTHANDLEIT             0x400   /* 2LS should handle the ev_q */
-#define EVENT_THREAD                   0x800   /* spawn thread to handle ev_q */
+#define EVENT_JUSTHANDLEIT             0x10000 /* 2LS should handle the ev_q */
+#define EVENT_THREAD                   0x20000 /* spawn thread to handle ev_q */
 
 /* Event Message Types */
 #define EV_NONE                                         0
index 5d7c345..31c74f9 100644 (file)
@@ -242,13 +242,11 @@ static void spam_public_msg(struct proc *p, struct event_msg *ev_msg,
        vc = TAILQ_FIRST(&p->inactive_vcs);
        if (vc) {       /* might be none in rare circumstances */
                if (try_spam_vcore(p, vcore2vcoreid(p, vc), ev_msg, ev_flags)) {
-                       /* Need to ensure the proc wakes up, but only if it was WAITING.
-                        * One way for this to happen is if a normal vcore was preempted
-                        * right as another vcore was yielding, and the preempted
-                        * message was sent after the last vcore yielded (which caused
-                        * us to be WAITING */
-                       if (p->state == PROC_WAITING)
-                               proc_wakeup(p); /* internally, this double-checks WAITING */
+                       /* It's possible that we're WAITING here.  EVENT_WAKEUP will handle
+                        * it.  One way for this to happen is if a normal vcore was
+                        * preempted right as another vcore was yielding, and the preempted
+                        * message was sent after the last vcore yielded (which caused us to
+                        * be WAITING). */
                        return;
                }
        }
@@ -261,8 +259,8 @@ ultimate_fallback:
         * grabs the vmr_lock and pte_lock. */
        spin_lock(&p->proc_lock);
        if (p->state != PROC_WAITING) {
-               /* We need to check the online and bulk_preempt lists again, now that we are
-                * sure no one is messing with them.  If we're WAITING, we can skip
+               /* We need to check the online and bulk_preempt lists again, now that we
+                * are sure no one is messing with them.  If we're WAITING, we can skip
                 * these (or assert they are empty!). */
                vc = TAILQ_FIRST(&p->online_vcs);
                if (vc) {
@@ -290,12 +288,10 @@ ultimate_fallback:
         * above */
        set_vcore_msgable(vcore2vcoreid(p, vc));
        /* The first event to catch the process with no online/bp vcores will need
-        * to wake it up.  (We could be RUNNABLE_M here if another event already woke
-        * us.) and we didn't get lucky with the penultimate fallback.
-        * proc_wakeup (and __proc_wakeup()) will check for WAITING. */
+        * to wake it up, which is handled elsewhere if they requested EVENT_WAKEUP.
+        * We could be RUNNABLE_M here if another event already woke us and we
+        * didn't get lucky with the penultimate fallback. */
        spin_unlock(&p->proc_lock);
-       proc_wakeup(p);
-       return;
 }
 
 /* Helper: sends an indirection event for an ev_q, preferring vcoreid */
@@ -413,7 +409,7 @@ void send_event(struct proc *p, struct event_queue *ev_q, struct event_msg *msg,
         * (via APPRO or whatever). */
        if (ev_q->ev_flags & EVENT_SPAM_PUBLIC) {
                spam_public_msg(p, msg, vcoreid, ev_q->ev_flags);
-               goto out;
+               goto wakeup;
        }
        /* We aren't spamming and we know the default vcore, and now we need to
         * figure out which mbox to use.  If they provided an mbox, we'll use it.
@@ -450,6 +446,9 @@ void send_event(struct proc *p, struct event_queue *ev_q, struct event_msg *msg,
                /* they may want an IPI despite not wanting an INDIR */
                try_notify(p, vcoreid, ev_q->ev_flags);
        }
+wakeup:
+       if ((ev_q->ev_flags & EVENT_WAKEUP) && (p->state == PROC_WAITING))
+               proc_wakeup(p);
        /* Fall through */
 out:
        /* Return to the old address space. */
index bd26064..8d6204f 100644 (file)
@@ -70,7 +70,7 @@ int main(int argc, char **argv)
        /* I think this is all the flags we need; gotta write that dissertation
         * chapter (and event how-to)!  We may get more than one event per alarm, if
         * we have concurrent preempts/yields. */
-       ev_q->ev_flags = EVENT_IPI | EVENT_SPAM_PUBLIC;
+       ev_q->ev_flags = EVENT_IPI | EVENT_SPAM_PUBLIC | EVENT_WAKEUP;
        /* Register the ev_q for our alarm */
        ret = snprintf(path, sizeof(path), "evq %llx", ev_q);
        ret = write(ctlfd, path, ret);
index 6d2cc22..db480ad 100644 (file)
@@ -131,7 +131,7 @@ static void init_alarm_service(void)
        /* We could get multiple events for a single alarm.  It's okay, since
         * __trigger can handle spurious upcalls.  If it ever is not okay, then use
         * an INDIR (probably with SPAM_INDIR too) instead of SPAM_PUBLIC. */
-       ev_q->ev_flags = EVENT_IPI | EVENT_SPAM_PUBLIC;
+       ev_q->ev_flags = EVENT_IPI | EVENT_SPAM_PUBLIC | EVENT_WAKEUP;
        ret = snprintf(path, sizeof(path), "evq %llx", ev_q);
        ret = write(ctlfd, path, ret);
        if (ret <= 0) {
index 065ae18..4be0672 100644 (file)
@@ -227,7 +227,8 @@ void init_posix_signals(void)
        register_ev_handler(EV_POSIX_SIGNAL, handle_event, 0);
        posix_sig_ev_q = get_big_event_q();
        assert(posix_sig_ev_q);
-       posix_sig_ev_q->ev_flags = EVENT_IPI | EVENT_INDIR | EVENT_SPAM_INDIR;
+       posix_sig_ev_q->ev_flags = EVENT_IPI | EVENT_INDIR | EVENT_SPAM_INDIR |
+                                  EVENT_WAKEUP;
        register_kevent_q(posix_sig_ev_q, EV_POSIX_SIGNAL);
        wfl_init(&sigdata_list);
 }
index 83f048e..f10bb47 100644 (file)
@@ -115,7 +115,7 @@ void uthread_mcp_init()
        register_ev_handler(EV_CHECK_MSGS, handle_vc_indir, 0);
        preempt_ev_q = get_event_q();   /* small ev_q, mostly a vehicle for flags */
        preempt_ev_q->ev_flags = EVENT_IPI | EVENT_SPAM_PUBLIC | EVENT_VCORE_APPRO |
-                                                        EVENT_VCORE_MUST_RUN;
+                                                        EVENT_VCORE_MUST_RUN | EVENT_WAKEUP;
        /* Tell the kernel to use the ev_q (it's settings) for the two types.  Note
         * that we still have two separate handlers.  We just want the events
         * delivered in the same way.  If we ever want to have a big_event_q with
index 83bf7f1..f471c78 100644 (file)
@@ -638,7 +638,7 @@ void __attribute__((constructor)) pthread_lib_init(void)
                /* Each vcore needs to point to a non-VCPD ev_q */
                sysc_mgmt[i].ev_q = get_big_event_q_raw();
                sysc_mgmt[i].ev_q->ev_flags = EVENT_IPI | EVENT_INDIR |
-                                             EVENT_SPAM_INDIR;
+                                             EVENT_SPAM_INDIR | EVENT_WAKEUP;
                sysc_mgmt[i].ev_q->ev_vcore = i;
                ucq_init_raw(&sysc_mgmt[i].ev_q->ev_mbox->ev_msgs, 
                             mmap_block + (2 * i    ) * PGSIZE, 
@@ -659,7 +659,7 @@ void __attribute__((constructor)) pthread_lib_init(void)
        for (int i = 0; i < max_vcores(); i++) {
                sysc_mgmt[i].ev_q = get_event_q();
                sysc_mgmt[i].ev_q->ev_flags = EVENT_IPI | EVENT_INDIR |
-                                             EVENT_SPAM_INDIR;
+                                             EVENT_SPAM_INDIR | EVENT_WAKEUP;
                sysc_mgmt[i].ev_q->ev_vcore = i;
                sysc_mgmt[i].ev_q->ev_mbox = sysc_mbox;
        }