Allow vcore_tick_* to be called from uthreads
authorBarret Rhoden <brho@cs.berkeley.edu>
Fri, 5 Aug 2016 00:34:19 +0000 (17:34 -0700)
committerBarret Rhoden <brho@cs.berkeley.edu>
Wed, 10 Aug 2016 19:35:59 +0000 (15:35 -0400)
Previously, they were designed for use from sched_entry(), and thus
vcore context.  There are cases where scheduler functions that aren't in
vcore context might want to mess with the *current vcore's* timer tick.

To do this, I had to stop using the TLS variable, and use a constructor
instead.  Otherwise, the uthread would use its own __vc_tick.  When a
uthread disabled notifs, it appears to be in vcore context to other
vcores and the kernel.  However, it is not actually in vcore context, at
least when it comes to TLS and stacks.

Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
user/benchutil/include/benchutil/vcore_tick.h
user/benchutil/vcore_tick.c

index 50781bd..8c1f4ed 100644 (file)
  *             vcore_tick_enable(10000);
  *
  * will only set one alarm.  The latter two calls just set the period to 10000
- * usec. */
+ * usec.
+ *
+ * These functions can be called from uthread context and will affect their
+ * *current* vcore, but once they return, the uthread could be on a different
+ * vcore. */
 
 #pragma once
 
index 71529bb..ebbd908 100644 (file)
@@ -5,6 +5,7 @@
  * Vcore timer ticks. */
 
 #include <parlib/vcore.h>
+#include <parlib/uthread.h>
 #include <parlib/assert.h>
 #include <parlib/tsc-compat.h>
 #include <parlib/arch/bitmask.h>
@@ -30,7 +31,19 @@ struct vcore_tick {
        struct event_queue                      *ev_q;
 };
 
-static __thread struct vcore_tick __vc_tick;
+static struct vcore_tick *__vc_ticks;
+
+static void __attribute__((constructor)) vcore_tick_lib_init(void)
+{
+       __vc_ticks = calloc(max_vcores(), sizeof(struct vcore_tick));
+       assert(__vc_ticks);
+}
+
+/* Only call this from vcore context or with notifs disabled. */
+static struct vcore_tick *get_my_tick(void)
+{
+       return &__vc_ticks[vcore_id()];
+}
 
 static void vcore_tick_init(struct vcore_tick *vc_tick)
 {
@@ -62,8 +75,10 @@ static void __vcore_tick_start(struct vcore_tick *vc_tick, uint64_t from_now)
  * on.  You also can update the period of an already-running tick. */
 void vcore_tick_enable(uint64_t period_usec)
 {
-       struct vcore_tick *vc_tick = &__vc_tick;
+       struct vcore_tick *vc_tick;
 
+       uth_disable_notifs();
+       vc_tick = get_my_tick();
        if (vc_tick->state == VC_TICK_PREINIT)
                vcore_tick_init(vc_tick);
 
@@ -74,15 +89,18 @@ void vcore_tick_enable(uint64_t period_usec)
                __vcore_tick_start(vc_tick, vc_tick->period_ticks);
                vc_tick->state = VC_TICK_ENABLED;
        }
+       uth_enable_notifs();
 }
 
 /* Disables the timer tick.  You can call this repeatedly.  It is possible that
  * you will still have a timer tick pending after this returns. */
 void vcore_tick_disable(void)
 {
-       struct vcore_tick *vc_tick = &__vc_tick;
+       struct vcore_tick *vc_tick;
        int ret;
 
+       uth_disable_notifs();
+       vc_tick = get_my_tick();
        if (vc_tick->state == VC_TICK_PREINIT)
                vcore_tick_init(vc_tick);
 
@@ -91,6 +109,7 @@ void vcore_tick_disable(void)
                assert(!ret);
                vc_tick->state = VC_TICK_DISABLED;
        }
+       uth_enable_notifs();
 }
 
 /* Polls the vcore timer tick.  Returns the number of times it has expired, 0
@@ -98,11 +117,13 @@ void vcore_tick_disable(void)
  * is still turned on. */
 int vcore_tick_poll(void)
 {
-       struct vcore_tick *vc_tick = &__vc_tick;
+       struct vcore_tick *vc_tick;
        struct evbitmap *evbm;
        int ret = 0;
        uint64_t from_now, virtual_now;
 
+       uth_disable_notifs();
+       vc_tick = get_my_tick();
        if (vc_tick->state == VC_TICK_PREINIT)
                vcore_tick_init(vc_tick);
 
@@ -126,6 +147,7 @@ int vcore_tick_poll(void)
                 * polling for the event.  The kernel will still __notify us, setting
                 * notif_pending, and we'll notice the next time we attempt to leave
                 * vcore context. */
+               uth_enable_notifs();
                return 0;
        }
        /* Don't care about clobbering neighboring bits (non-atomic op) */
@@ -148,5 +170,6 @@ int vcore_tick_poll(void)
         * get caught in the while loop forever. */
        from_now = vc_tick->next_deadline - virtual_now;
        __vcore_tick_start(vc_tick, from_now);
+       uth_enable_notifs();
        return ret;
 }