parlib: Allow cpu_relax_vc() calls from uthreads
authorBarret Rhoden <brho@cs.berkeley.edu>
Fri, 14 Apr 2017 15:23:02 +0000 (11:23 -0400)
committerBarret Rhoden <brho@cs.berkeley.edu>
Wed, 3 May 2017 16:13:02 +0000 (12:13 -0400)
This goes a little farther than commit 2ee62d285f56 ("parlib: Fix assertion
in cpu_relax_vc()").  Not only is it OK for uthreads to call
cpu_relax_vc(), but they should be able to call it regardless of whether
notifs are disabled or not.

Basically, any uthread can always call this.  If they aren't responsible
for handling preemption issues, they just do the normal cpu_relax(), which
is just a compiler barrier and "pause" on x86.

Here's how to think about this.  If we're spinning in userspace and waiting
on another core in userspace, we need to consider that the other core has
been preempted.  Our current preemption code is set up so that we'll
receive a notif (software IPI) if another core is preempted.  So if we have
notifs enabled, then we don't need to do anything fancy.  If notifs are
disabled, then we might not see the preemption message.  In that case, we
need to call ensure_vcore_runs() and all that (polling the vcoremap).

Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
user/parlib/syscall.c
user/parlib/vcore.c

index 8c61542..8b18ef4 100644 (file)
@@ -126,6 +126,9 @@ int sys_change_vcore(uint32_t vcoreid, bool enable_my_notif)
         * unlocking the proc, before finish_sysc()), and the act of finishing would
         * write onto our stack.  Thus we use the per-vcore struct. */
        int flags;
+
+       /* Sanity check.  Uthreads can call this, but only when notifs disabled. */
+       assert(!notif_is_enabled(vcore_id()));
        /* Need to wait while a previous syscall is not done or locked.  Since this
         * should only be called from VC ctx, we'll just spin.  Should be extremely
         * rare.  Note flags is initialized to SC_DONE. */
index 2773640..fb4b5c9 100644 (file)
@@ -456,17 +456,24 @@ void ensure_vcore_runs(uint32_t vcoreid)
 }
 
 #define NR_RELAX_SPINS 1000
-/* If you are spinning in vcore context and it is likely that you don't know who
- * you are waiting on, call this.  It will spin for a bit before firing up the
- * potentially expensive __ensure_all_run().  Don't call this from uthread
- * context.  sys_change_vcore will probably mess you up. */
-void cpu_relax_vc(uint32_t vcoreid)
+/* If you are spinning and waiting on another vcore, call this.  Pass in the
+ * vcoreid of the core you are waiting on, or your own vcoreid if you don't
+ * know.  It will spin for a bit before firing up the potentially expensive
+ * __ensure_all_run(). */
+void cpu_relax_vc(uint32_t other_vcoreid)
 {
        static __thread unsigned int __vc_relax_spun = 0;
-       assert(!notif_is_enabled(vcore_id()));
+
+       /* Uthreads with notifs enabled can just spin normally.  This actually
+        * depends on the 2LS preemption policy.  Currently, we receive notifs
+        * whenever another core is preempted, so we don't need to poll. */
+       if (notif_is_enabled(vcore_id())) {
+               cpu_relax();
+               return;
+       }
        if (__vc_relax_spun++ >= NR_RELAX_SPINS) {
-               /* if vcoreid == vcore_id(), this might be expensive */
-               ensure_vcore_runs(vcoreid);
+               /* if other_vcoreid == vcore_id(), this might be expensive */
+               ensure_vcore_runs(other_vcoreid);
                __vc_relax_spun = 0;
        }
        cpu_relax();