Rename EVENT_FALLBACK -> EVENT_SPAM_INDIR (XCC)
authorBarret Rhoden <brho@cs.berkeley.edu>
Mon, 3 Aug 2015 22:41:09 +0000 (18:41 -0400)
committerBarret Rhoden <brho@cs.berkeley.edu>
Mon, 28 Sep 2015 19:14:00 +0000 (15:14 -0400)
"Fallback" was the original name for it, since it was the back-up plan
when a vcore was offline.  Once SPAM_PUBLIC came out, it was more clear
that it's really spamming an INDIR.  This came out of trying to explain
it: http://www.eecs.berkeley.edu/Pubs/TechRpts/2014/EECS-2014-223.pdf.

Other than comments and the rename, the only functional change is the
removal of a printk.  For now, it's possible to have an INDIR without
spamming the INDIR.  I have a couple half-baked use cases for it.

Reinstall your kernel headers (make xcc-install-headers)

Documentation/async_events.txt
kern/include/ros/event.h
kern/src/event.c
user/benchutil/alarm.c
user/parlib/signal.c
user/parlib/uthread.c
user/parlib/vcore.c
user/pthread/pthread.c

index 0e4778a..767c6cf 100644 (file)
@@ -335,19 +335,20 @@ 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
 at any time (proc_notify()).
 
-3.3 IPIs, Indirection Events, and Fallback
+3.3 IPIs, Indirection Events, and Fallback (Spamming Indirs)
 ----------------------------------------------
-An ev_q can ask for an IPI, an indirection event, and a fallback in case a vcore
-is offline.  Or any combination of these.  Note that these have little to do
-with the actual message being sent.  The actual message is dropped in the
-ev_mbox pointed to by the ev_q.
+An ev_q can ask for an IPI, for an indirection event, and for an indirection
+event to be spammed in case a vcore is offline (sometimes called the 'fallback'
+option.  Or any combination of these.  Note that these have little to do with
+the actual message being sent.  The actual message is dropped in the ev_mbox
+pointed to by the ev_q.
 
 The main use for all of this is for syscalls.  If you want to receive an event
 when a syscall completes or has a change in status, simply allocate an event_q,
 and point the syscall at it.  syscall: ev_q* -> "vcore for IPI, syscall message
 in the ev_q mbox", etc.  You can also point it to an existing ev_q.  Pthread
 code has examples of two ways to do this.  Both have per vcore ev_qs, requesting
-IPIs, INDIRS, and FALLBACK.  One way is to have an ev_mbox per vcore, and
+IPIs, INDIRS, and SPAM_INDIR.  One way is to have an ev_mbox per vcore, and
 another is to have a global ev_mbox that all ev_qs point to.  As a side note, if
 you do the latter, you don't need to worry about a vcore's ev_q if it gets
 preempted: just check the global ev_mbox (which is done by checking your own
@@ -376,41 +377,41 @@ 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
+own ev_q and set flags for INDIR, SPAM_INDIR, 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
+3.3.2: Spamming Indirs / Fallback
 ---------------
 Both IPI and INDIR need an actual vcore.  If that vcore is unavailable and if
-EVENT_FALLBACK is set, the kernel will pick another vcore and send the messages
-there.  This allows an ev_q to be set up to handle work when the vcore is
-online, while allowing the program to handle events when that core yields,
+EVENT_SPAM_INDIR is set, the kernel will pick another vcore and send the
+messages there.  This allows an ev_q to be set up to handle work when the vcore
+is online, while allowing the program to handle events when that core yields,
 without having to reset all of its ev_qs to point to "known" available vcores
 (and avoiding those races).  Note 'online' is synonymous with 'mapped', when
-talking about vcores.  A vcore technically isn't always online, only destined to
-be online, when it is mapped to a pcore (kmsg on the way, etc).  It's easiest to
-think of it being online for the sake of this discussion.
-
-One question is whether or not 2LSs need a FALLBACK flag for their ev_qs.  The
-main use for FALLBACK is so that vcores can yield.  (Note that fallback won't
-help you *miss* INDIR messages in the event of a preemption; you can always lose
-that race due to it taking too long to process the messages).  An alternative
-would be for vcores to pick another vcore and change all of its ev_qs to that
-vcore.  There are a couple problems with this.  One is that it'll be a pain to
-get those ev_qs back when the vcore comes back online (if ever).  Another issue
-is that other vcores will build up a list of ev_qs that they aren't aware of,
-which will be hard to deal with when *they* yield.  FALLBACK avoids all of those
-problems.
-
-An important aspect of FALLBACK is that it works with yielded vcores, not
-preempted vcores.  It could be that there are no cores that are online, but
+talking about vcores.  A vcore technically isn't always online, only destined
+to be online, when it is mapped to a pcore (kmsg on the way, etc).  It's
+easiest to think of it being online for the sake of this discussion.
+
+One question is whether or not 2LSs need a SPAM_INDIR flag for their ev_qs.
+The main use for SPAM_INDIR is so that vcores can yield.  (Note that fallback
+won't help you *miss* INDIR messages in the event of a preemption; you can
+always lose that race due to it taking too long to process the messages).  An
+alternative would be for vcores to pick another vcore and change all of its
+ev_qs to that vcore.  There are a couple problems with this.  One is that it'll
+be a pain to get those ev_qs back when the vcore comes back online (if ever).
+Another issue is that other vcores will build up a list of ev_qs that they
+aren't aware of, which will be hard to deal with when *they* yield.  SPAM_INDIR
+avoids all of those problems.
+
+An important aspect of spamming indirs is that it works with yielded vcores,
+not preempted vcores.  It could be that there are no cores that are online, but
 there should always be at least one core that *will* be online in the future, a
 core that the process didn't want to lose and will deal with in the future.  If
-not for this distinction, FALLBACK could fail.  An older idea would be to have
+not for this distinction, SPAM_INDIR could fail.  An older idea would be to have
 fallback send the msg to the desired vcore if there were no others.  This would
 not work if the vcore yielded and then the entire process was preempted or
 otherwise not running.  Another way to put this is that we need a field to
@@ -418,7 +419,7 @@ determine whether a vcore is offline temporarily or permanently.
 
 This is why we have the VCPD flag 'VC_CAN_RCV_MSG'.  It tells the kernel's event
 delivery code that the vcore will check the messages: it is an acceptable
-destination for a FALLBACK.  There are two reasons to put this in VCPD:
+destination for a spammed indir.  There are two reasons to put this in VCPD:
 1) Userspace can remotely turn off a vcore's msg reception.  This is necessary
 for handling preemption of a vcore that was in uthread context, so that we can
 remotely 'yield' the core without having to sys_change_vcore() (which I discuss
@@ -453,7 +454,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
+SPAM_INDIR doesn't protect you from preemptions.  A vcore can be preempted and
 have INDIRs in its VCPD.
 
 It is tempting to just use sys_change_vcore(), which will change the calling
@@ -481,7 +482,7 @@ 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,
+spammed 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.
 
index 9b167ba..fe16ad0 100644 (file)
@@ -19,7 +19,7 @@
 #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_FALLBACK                 0x020   /* spam INDIRs if the vcore's offline */
+#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 */
@@ -30,7 +30,7 @@
 #define EVENT_JUSTHANDLEIT             0x400   /* 2LS should handle the ev_q */
 #define EVENT_THREAD                   0x800   /* spawn thread to handle ev_q */
 
-/* Certain event flags apply to spam/fallback messages */
+/* Certain event flags apply to spam messages */
 #define EVENT_SPAM_FLAGS               (EVENT_IPI | EVENT_VCORE_MUST_RUN)
 
 /* Event Message Types */
@@ -101,7 +101,7 @@ struct event_queue_big {
 /* Vcore state flags.  K_LOCK means the kernel is writing */
 #define VC_K_LOCK                              0x001                           /* CASing with the kernel */
 #define VC_PREEMPTED                   0x002                           /* VC is preempted */
-#define VC_CAN_RCV_MSG                 0x004                           /* can receive FALLBACK */
+#define VC_CAN_RCV_MSG                 0x004                           /* someone will get msg */
 #define VC_UTHREAD_STEALING            0x008                           /* Uthread being stolen */
 #define VC_SCP_NOVCCTX                 0x010                           /* can't go into vc ctx */
 
index 880839b..7ec56ca 100644 (file)
@@ -186,7 +186,7 @@ static bool spam_list_member(struct vcore_tailq *list, struct proc *p,
 
 /* This makes sure ev_msg is sent to some vcore, preferring vcoreid.
  *
- * One of the goals of FALLBACK (and this func) is to allow processes to yield
+ * One of the goals of SPAM_INDIR (and this func) is to allow processes to yield
  * cores without fear of losing messages.  Even when yielding and getting
  * preempted, if your message is spammed, it will get to some vcore.  If
  * MUST_RUN is set, it'll get to a running vcore.  Messages that you send like
@@ -323,16 +323,21 @@ static void send_indir(struct proc *p, struct event_queue *ev_q,
        wmb();  /* force this write to happen before any event writes */
        local_msg.ev_type = EV_EVENT;
        local_msg.ev_arg3 = ev_q;
-       /* Don't care about FALLBACK, just send and be done with it.  TODO:
-        * considering getting rid of FALLBACK as an option and making it mandatory
-        * when you want an INDIR.  Having trouble thinking of when you'd want an
-        * INDIR but not a FALLBACK. */
-       if (!(ev_q->ev_flags & EVENT_FALLBACK)) {
-               printk("[kernel] INDIR requested without FALLBACK, prob a bug.\n");
+       /* If we're not spamming indirs, just send and be done with it.
+        *
+        * It's possible that the user does not want to poll their evq and wants an
+        * INDIR, but also doesn't care about sleeping or otherwise not getting the
+        * message right away.  The INDIR could sit in the VCPD of a vcore that
+        * doesn't run for a while.  Perhaps if the app always made sure VC 0 was
+        * on when it was running at all, and sent the INDIR there.  Or there was a
+        * per-vc evq that only needed to be handled when the VC turned on.  This
+        * gets at another aspect of INDIRs, other than it's need for "only once"
+        * operation: maybe the mbox type isn't a UCQ (like the VCPD mboxes). */
+       if (!(ev_q->ev_flags & EVENT_SPAM_INDIR)) {
                spam_vcore(p, vcoreid, &local_msg, ev_q->ev_flags);
                return;
        }
-       /* At this point, we actually want to send an INDIR (with FALLBACK).
+       /* At this point, we actually want to send and spam an INDIR.
         * This will guarantee the message makes it to some vcore.  For flags, we
         * only want to send flags relevant to spamming messages. */
        spam_public_msg(p, &local_msg, vcoreid, ev_q->ev_flags & EVENT_SPAM_FLAGS);
index b88c865..6d2cc22 100644 (file)
@@ -130,7 +130,7 @@ static void init_alarm_service(void)
        ev_q->ev_vcore = 0;
        /* 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/FALLBACK instead of SPAM_PUBLIC. */
+        * an INDIR (probably with SPAM_INDIR too) instead of SPAM_PUBLIC. */
        ev_q->ev_flags = EVENT_IPI | EVENT_SPAM_PUBLIC;
        ret = snprintf(path, sizeof(path), "evq %llx", ev_q);
        ret = write(ctlfd, path, ret);
index 5f4f318..065ae18 100644 (file)
@@ -227,7 +227,7 @@ 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_FALLBACK;
+       posix_sig_ev_q->ev_flags = EVENT_IPI | EVENT_INDIR | EVENT_SPAM_INDIR;
        register_kevent_q(posix_sig_ev_q, EV_POSIX_SIGNAL);
        wfl_init(&sigdata_list);
 }
index 6c88509..83f048e 100644 (file)
@@ -109,8 +109,8 @@ void uthread_mcp_init()
         * events should be spammed to vcores that are running, preferring whatever
         * the kernel thinks is appropriate.  And IPI them.
         *
-        * It is critical that these are either SPAM_PUB or INDIR|FALLBACK, so that
-        * yielding vcores do not miss the preemption messages. */
+        * It is critical that these are either SPAM_PUB or INDIR|SPAM_INDIR, so
+        * that yielding vcores do not miss the preemption messages. */
        register_ev_handler(EV_VCORE_PREEMPT, handle_vc_preempt, 0);
        register_ev_handler(EV_CHECK_MSGS, handle_vc_indir, 0);
        preempt_ev_q = get_event_q();   /* small ev_q, mostly a vehicle for flags */
@@ -841,8 +841,8 @@ static void handle_indirs(uint32_t rem_vcoreid)
        struct preempt_data *rem_vcpd = vcpd_of(rem_vcoreid);
        /* Turn off their message reception if they are still preempted.  If they
         * are no longer preempted, we do nothing - they will handle their own
-        * messages.  Turning on CAN_RCV will route this vcore's messages to
-        * fallback vcores (if applicable). */
+        * messages.  Turning off CAN_RCV will route this vcore's messages to
+        * fallback vcores (if those messages were 'spammed'). */
        do {
                old_flags = atomic_read(&rem_vcpd->flags);
                while (old_flags & VC_K_LOCK)
index 18d5655..b440c74 100644 (file)
@@ -344,8 +344,9 @@ void vcore_yield(bool preempt_pending)
         * to avoid the yield syscall if we have an event pending.  If there is one,
         * we want to unwind and return to the 2LS loop, where we may not want to
         * yield anymore.
-        * Note that the kernel only cares about CAN_RCV_MSG for the desired vcore,
-        * not for a FALLBACK.  */
+        * Note that the kernel only cares about CAN_RCV_MSG for the desired vcore;
+        * when spamming, it relies on membership of lists within the kernel.  Look
+        * at spam_list_member() for more info (k/s/event.c). */
        if (handle_events(vcoreid)) {
                __sync_fetch_and_or(&vcpd->flags, VC_CAN_RCV_MSG);
                return;
index 8fcfa9b..83bf7f1 100644 (file)
@@ -637,7 +637,8 @@ void __attribute__((constructor)) pthread_lib_init(void)
        for (int i = 0; i < max_vcores(); i++) {
                /* 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_FALLBACK;
+               sysc_mgmt[i].ev_q->ev_flags = EVENT_IPI | EVENT_INDIR |
+                                             EVENT_SPAM_INDIR;
                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, 
@@ -657,7 +658,8 @@ void __attribute__((constructor)) pthread_lib_init(void)
        ucq_init_raw(&sysc_mbox->ev_msgs, two_pages, two_pages + PGSIZE);
        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_FALLBACK;
+               sysc_mgmt[i].ev_q->ev_flags = EVENT_IPI | EVENT_INDIR |
+                                             EVENT_SPAM_INDIR;
                sysc_mgmt[i].ev_q->ev_vcore = i;
                sysc_mgmt[i].ev_q->ev_mbox = sysc_mbox;
        }