parlib: Move alarm/timer functions from benchutil
authorBarret Rhoden <brho@cs.berkeley.edu>
Thu, 6 Apr 2017 20:43:37 +0000 (16:43 -0400)
committerBarret Rhoden <brho@cs.berkeley.edu>
Wed, 3 May 2017 16:13:02 +0000 (12:13 -0400)
Certain functions are in benchutil because they couldn't be in parlib.  The
original function of this sort needed -libm (sqrt, IIRC).

These other timing functions were in benchutil since usec2tsc() was there,
which was back in 2013.  It turns out those didn't need to be in benchutil,
and they were moved about a year later in commit dd7547b8fc54 ("Moves some
timing func from benchutil to parlib").

Now that there's no reason to have those functions in benchutil, we can
move them to parlib.  I need to do this since I'd like to use alarms for
parlib's mutex.c functions.

Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
28 files changed:
tests/alarm.c
tests/evq_block.c
tests/getifaddrs.c
tests/listen1.c
tests/ping.c
tests/timerfd.c
tests/xmm.c
tools/apps/ipconfig/ipv6.c
tools/apps/ipconfig/main.c
user/benchutil/alarm.c [deleted file]
user/benchutil/include/benchutil/alarm.h [deleted file]
user/benchutil/include/benchutil/pvcalarm.h [deleted file]
user/benchutil/include/benchutil/vcore_tick.h [deleted file]
user/benchutil/pvcalarm.c [deleted file]
user/benchutil/vcore_tick.c [deleted file]
user/parlib/alarm.c [new file with mode: 0644]
user/parlib/include/parlib/alarm.h [new file with mode: 0644]
user/parlib/include/parlib/pvcalarm.h [new file with mode: 0644]
user/parlib/include/parlib/vcore_tick.h [new file with mode: 0644]
user/parlib/pvcalarm.c [new file with mode: 0644]
user/parlib/vcore_tick.c [new file with mode: 0644]
user/pthread/futex.c
user/pthread/profalarm.c
user/pthread/semaphore.c
user/pthread/semaphore.h
user/utest/alarm.c
user/utest/pvcalarm.c
user/vmm/sched.c

index 14c5f23..ce72778 100644 (file)
@@ -10,7 +10,7 @@
 #include <unistd.h>
 #include <parlib/event.h>
 #include <benchutil/measure.h>
-#include <benchutil/alarm.h>
+#include <parlib/alarm.h>
 #include <parlib/uthread.h>
 #include <parlib/timing.h>
 
index db70fe4..49a050e 100644 (file)
@@ -9,7 +9,7 @@
 #include <parlib/event.h>
 #include <parlib/timing.h>
 #include <parlib/uthread.h>
-#include <benchutil/alarm.h>
+#include <parlib/alarm.h>
 
 static struct event_queue *get_ectlr_evq(void)
 {
index c8e2277..6783386 100644 (file)
@@ -18,7 +18,7 @@
 #include <parlib/timing.h>
 #include <parlib/tsc-compat.h>
 #include <parlib/printf-ext.h>
-#include <benchutil/alarm.h>
+#include <parlib/alarm.h>
 #include <ndblib/ndb.h>
 #include <ifaddrs.h>
 
index 05bf753..5421175 100644 (file)
@@ -20,7 +20,7 @@
 #include <parlib/timing.h>
 #include <parlib/tsc-compat.h>
 #include <parlib/printf-ext.h>
-#include <benchutil/alarm.h>
+#include <parlib/alarm.h>
 #include <ndblib/ndb.h>
 #include <fcntl.h>
 
index 91b213b..e56c64c 100644 (file)
@@ -18,7 +18,7 @@
 #include <parlib/timing.h>
 #include <parlib/tsc-compat.h>
 #include <parlib/printf-ext.h>
-#include <benchutil/alarm.h>
+#include <parlib/alarm.h>
 #include <ndblib/ndb.h>
 
 #define NR_MSG                         4
index 2974c7f..0c34887 100644 (file)
@@ -47,7 +47,7 @@
 
 #include <sys/timerfd.h>
 #include <sys/select.h>
-#include <benchutil/alarm.h>
+#include <parlib/alarm.h>
 #include <parlib/uthread.h>
 
 struct tmr_type {
index ccd1ba9..298eb30 100644 (file)
@@ -8,7 +8,7 @@
 #include <pthread.h>
 #include <stdlib.h>
 #include <unistd.h>
-#include <benchutil/pvcalarm.h>
+#include <parlib/pvcalarm.h>
 
 static void nothing() {}
 
index b48d505..94cfb51 100644 (file)
@@ -13,7 +13,7 @@
 //     RA means Router Advertisement
 //
 
-#include <benchutil/alarm.h>
+#include <parlib/alarm.h>
 #include <iplib/iplib.h>
 #include <parlib/common.h>
 #include <parlib/parlib.h>
index 9aa0712..286c3aa 100644 (file)
@@ -11,7 +11,7 @@
  * ipconfig - configure parameters of an ip stack
  */
 
-#include <benchutil/alarm.h>
+#include <parlib/alarm.h>
 #include <iplib/iplib.h>
 #include <ndblib/ndb.h>
 #include <parlib/common.h>
diff --git a/user/benchutil/alarm.c b/user/benchutil/alarm.c
deleted file mode 100644 (file)
index 7ecc4cf..0000000
+++ /dev/null
@@ -1,485 +0,0 @@
-/* Copyright (c) 2013 The Regents of the University of California
- * Barret Rhoden <brho@cs.berkeley.edu>
- * See LICENSE for details.
- *
- * Userspace alarms.  There are lower level helpers to build your own alarms
- * from the #alarm device and an alarm service, based off a slimmed down version
- * of the kernel alarms.  Under the hood, the user alarm uses the #alarm service
- * for the root of the alarm chain.
- *
- * There's only one timer chain, unlike in the kernel, for the entire process.
- * If you want one-off timers unrelated to the chain (and sent to other vcores),
- * use #alarm directly.
- *
- * Your handlers will run from vcore context.
- *
- * Code differences from the kernel (for future porting):
- * - init_alarm_service, run as a constructor
- * - set_alarm() and friends are __tc_set_alarm(), passing global_tchain.
- * - reset_tchain_interrupt() uses #alarm
- * - removed anything related to semaphores or kthreads
- * - spinlocks -> spin_pdr_locks
- * - ev_q wrappers for converting #alarm events to __triggers
- * - printks, and other minor stuff. */
-
-#include <sys/queue.h>
-#include <sys/time.h>
-#include <benchutil/alarm.h>
-#include <stdio.h>
-#include <parlib/assert.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <parlib/parlib.h>
-#include <parlib/event.h>
-#include <benchutil/measure.h>
-#include <parlib/uthread.h>
-#include <parlib/spinlock.h>
-#include <parlib/timing.h>
-#include <sys/plan9_helpers.h>
-#include <sys/fork_cb.h>
-
-/* Helper to get your own alarm.   If you don't care about a return value, pass
- * 0 and it'll be ignored.  The alarm is built, but has no evq or timer set. */
-int devalarm_get_fds(int *ctlfd_r, int *timerfd_r, int *alarmid_r)
-{
-       int ctlfd, timerfd, alarmid, ret;
-       char buf[20];
-       char path[32];
-
-       ctlfd = open("#alarm/clone", O_RDWR | O_CLOEXEC);
-       if (ctlfd < 0)
-               return -1;
-       ret = read(ctlfd, buf, sizeof(buf) - 1);
-       if (ret <= 0)
-               return -1;
-       buf[ret] = 0;
-       alarmid = atoi(buf);
-       snprintf(path, sizeof(path), "#alarm/a%s/timer", buf);
-       timerfd = open(path, O_RDWR | O_CLOEXEC);
-       if (timerfd < 0)
-               return -1;
-       if (ctlfd_r)
-               *ctlfd_r = ctlfd;
-       else
-               close(ctlfd);
-       if (timerfd_r)
-               *timerfd_r = timerfd;
-       else
-               close(timerfd);
-       if (alarmid_r)
-               *alarmid_r = alarmid;
-       return 0;
-}
-
-int devalarm_set_evq(int timerfd, struct event_queue *ev_q, int alarmid)
-{
-       struct fd_tap_req tap_req = {0};
-
-       tap_req.fd = timerfd;
-       tap_req.cmd = FDTAP_CMD_ADD;
-       tap_req.filter = FDTAP_FILT_WRITTEN;
-       tap_req.ev_id = EV_ALARM;
-       tap_req.ev_q = ev_q;
-       tap_req.data = (void*)(long)alarmid;
-       if (sys_tap_fds(&tap_req, 1) != 1)
-               return -1;
-       return 0;
-}
-
-int devalarm_set_time(int timerfd, uint64_t tsc_time)
-{
-       return write_hex_to_fd(timerfd, tsc_time);
-}
-
-int devalarm_get_id(struct event_msg *ev_msg)
-{
-       if (!ev_msg)
-               return -1;
-       return (int)(long)ev_msg->ev_arg3;
-}
-
-int devalarm_disable(int timerfd)
-{
-       return write_hex_to_fd(timerfd, 0);
-}
-
-/* Helpers, basically renamed kernel interfaces, with the *tchain. */
-static void __tc_locked_set_alarm(struct timer_chain *tchain,
-                                  struct alarm_waiter *waiter);
-static void __tc_set_alarm(struct timer_chain *tchain,
-                           struct alarm_waiter *waiter);
-static bool __tc_unset_alarm(struct timer_chain *tchain,
-                             struct alarm_waiter *waiter);
-static void __tc_reset_alarm_abs(struct timer_chain *tchain,
-                                 struct alarm_waiter *waiter,
-                                 uint64_t abs_time);
-static void handle_user_alarm(struct event_msg *ev_msg, unsigned int ev_type,
-                              void *data);
-
-/* One chain to rule them all. */
-struct timer_chain global_tchain;
-
-/* Helper, resets the earliest/latest times, based on the elements of the list.
- * If the list is empty, we set the times to be the 12345 poison time.  Since
- * the list is empty, the alarm shouldn't be going off. */
-static void reset_tchain_times(struct timer_chain *tchain)
-{
-       if (TAILQ_EMPTY(&tchain->waiters)) {
-               tchain->earliest_time = ALARM_POISON_TIME;
-               tchain->latest_time = ALARM_POISON_TIME;
-       } else {
-               tchain->earliest_time = TAILQ_FIRST(&tchain->waiters)->wake_up_time;
-               tchain->latest_time =
-                       TAILQ_LAST(&tchain->waiters, awaiters_tailq)->wake_up_time;
-       }
-}
-
-static void devalarm_forked(void)
-{
-       /* We need to poison the FDs too, in case the child attempts to use the
-        * alarms.  It'd be chaos if they read/wrote to an arbitrary open FD. */
-       close(global_tchain.ctlfd);
-       global_tchain.ctlfd = -42;
-       close(global_tchain.timerfd);
-       global_tchain.timerfd = -42;
-}
-
-static void __attribute__((constructor)) init_alarm_service(void)
-{
-       int ctlfd, timerfd, alarmid;
-       struct event_queue *ev_q;
-       static struct fork_cb devalarm_fork_cb = {.func = devalarm_forked};
-
-       /* Sets up timer chain (only one chain per process) */
-       spin_pdr_init(&global_tchain.lock);
-       TAILQ_INIT(&global_tchain.waiters);
-       reset_tchain_times(&global_tchain);
-
-       if (devalarm_get_fds(&ctlfd, &timerfd, &alarmid)) {
-               perror("Useralarm: devalarm_get_fds");
-               return;
-       }
-       /* Since we're doing SPAM_PUBLIC later, we actually don't need a big ev_q.
-        * But someone might copy/paste this and change a flag. */
-       register_ev_handler(EV_ALARM, handle_user_alarm, 0);
-       if (!(ev_q = get_eventq(EV_MBOX_UCQ))) {
-               perror("Useralarm: Failed ev_q");
-               return;
-       }
-       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 (probably with SPAM_INDIR too) instead of SPAM_PUBLIC. */
-       ev_q->ev_flags = EVENT_IPI | EVENT_SPAM_PUBLIC | EVENT_WAKEUP;
-       if (devalarm_set_evq(timerfd, ev_q, alarmid)) {
-               perror("set_alarm_evq");
-               return;
-       }
-       /* now the alarm is all set, just need to write the timer whenever we want
-        * it to go off. */
-       global_tchain.alarmid = alarmid;
-       global_tchain.ctlfd = ctlfd;
-       global_tchain.timerfd = timerfd;
-       global_tchain.ev_q = ev_q;      /* mostly for debugging */
-       register_fork_cb(&devalarm_fork_cb);
-}
-
-/* Initializes a new awaiter. */
-void init_awaiter(struct alarm_waiter *waiter,
-                  void (*func) (struct alarm_waiter *awaiter))
-{
-       waiter->wake_up_time = ALARM_POISON_TIME;
-       assert(func);
-       waiter->func = func;
-       waiter->on_tchain = FALSE;
-}
-
-/* Give this the absolute time.  For now, abs_time is the TSC time that you want
- * the alarm to go off. */
-static void __set_awaiter_abs(struct alarm_waiter *waiter, uint64_t abs_time)
-{
-       waiter->wake_up_time = abs_time;
-}
-
-/* Give this the absolute unix time (in microseconds) that you want the alarm
- * to go off. */
-void set_awaiter_abs_unix(struct alarm_waiter *waiter, uint64_t abs_usec)
-{
-       __set_awaiter_abs(waiter, epoch_nsec_to_tsc(abs_usec * 1000));
-}
-
-/* Give this a relative time from now, in microseconds.  This might be easier to
- * use than dealing with the TSC. */
-void set_awaiter_rel(struct alarm_waiter *waiter, uint64_t usleep)
-{
-       uint64_t now, then;
-       now = read_tsc();
-       then = now + usec2tsc(usleep);
-       /* This will go off if we wrap-around the TSC.  It'll never happen for legit
-        * values, but this might catch some bugs with large usleeps. */
-       assert(now <= then);
-       __set_awaiter_abs(waiter, then);
-}
-
-/* Increment the timer that was already set, so that it goes off usleep usec
- * from the previous tick.  This is different than 'rel' in that it doesn't care
- * about when 'now' is. */
-void set_awaiter_inc(struct alarm_waiter *waiter, uint64_t usleep)
-{
-       assert(waiter->wake_up_time != ALARM_POISON_TIME);
-       waiter->wake_up_time += usec2tsc(usleep);
-}
-
-/* User interface to the global tchain */
-void __set_alarm(struct alarm_waiter *waiter)
-{
-       __tc_locked_set_alarm(&global_tchain, waiter);
-}
-
-void set_alarm(struct alarm_waiter *waiter)
-{
-       __tc_set_alarm(&global_tchain, waiter);
-}
-
-bool unset_alarm(struct alarm_waiter *waiter)
-{
-       return __tc_unset_alarm(&global_tchain, waiter);
-}
-
-void reset_alarm_abs(struct alarm_waiter *waiter, uint64_t abs_time)
-{
-       __tc_reset_alarm_abs(&global_tchain, waiter, abs_time);
-}
-
-/* Helper, makes sure the kernel alarm is turned on at the right time. */
-static void reset_tchain_interrupt(struct timer_chain *tchain)
-{
-       if (TAILQ_EMPTY(&tchain->waiters)) {
-               /* Turn it off */
-               printd("Turning alarm off\n");
-               if (devalarm_disable(tchain->timerfd)) {
-                       printf("Useralarm: unable to disarm alarm!\n");
-                       return;
-               }
-       } else {
-               /* Make sure it is on and set to the earliest time */
-               assert(tchain->earliest_time != ALARM_POISON_TIME);
-               /* TODO: check for times in the past or very close to now */
-               printd("Turning alarm on for %llu\n", tchain->earliest_time);
-               if (devalarm_set_time(tchain->timerfd, tchain->earliest_time)) {
-                       perror("Useralarm: Failed to set timer");
-                       return;
-               }
-       }
-}
-
-/* When an awaiter's time has come, this gets called. */
-static void wake_awaiter(struct alarm_waiter *waiter)
-{
-       waiter->on_tchain = FALSE;
-       cmb();  /* enforce the on_tchain write before the handlers */
-       waiter->func(waiter);
-}
-
-/* This is called when the kernel alarm triggers a tchain, and needs to wake up
- * everyone whose time is up.  Called from vcore context. */
-static void __trigger_tchain(struct timer_chain *tchain)
-{
-       struct alarm_waiter *i, *temp;
-       uint64_t now = read_tsc();
-       bool changed_list = FALSE;
-       spin_pdr_lock(&tchain->lock);
-       TAILQ_FOREACH_SAFE(i, &tchain->waiters, next, temp) {
-               printd("Trying to wake up %p who is due at %llu and now is %llu\n",
-                      i, i->wake_up_time, now);
-               /* TODO: Could also do something in cases where we're close to now */
-               if (i->wake_up_time <= now) {
-                       changed_list = TRUE;
-                       TAILQ_REMOVE(&tchain->waiters, i, next);
-                       /* Don't touch the waiter after waking it, since it could be in use
-                        * on another core (and the waiter can be clobbered as the kthread
-                        * unwinds its stack).  Or it could be kfreed */
-                       wake_awaiter(i);
-               } else {
-                       break;
-               }
-       }
-       if (changed_list) {
-               reset_tchain_times(tchain);
-       }
-       /* Need to reset the interrupt no matter what */
-       reset_tchain_interrupt(tchain);
-       spin_pdr_unlock(&tchain->lock);
-}
-
-static void handle_user_alarm(struct event_msg *ev_msg, unsigned int ev_type,
-                              void *data)
-{
-       assert(ev_type == EV_ALARM);
-       if (devalarm_get_id(ev_msg) == global_tchain.alarmid)
-               __trigger_tchain(&global_tchain);
-}
-
-/* Helper, inserts the waiter into the tchain, returning TRUE if we still need
- * to reset the tchain interrupt.  Caller holds the lock. */
-static bool __insert_awaiter(struct timer_chain *tchain,
-                             struct alarm_waiter *waiter)
-{
-       struct alarm_waiter *i, *temp;
-       /* This will fail if you don't set a time */
-       assert(waiter->wake_up_time != ALARM_POISON_TIME);
-       waiter->on_tchain = TRUE;
-       /* Either the list is empty, or not. */
-       if (TAILQ_EMPTY(&tchain->waiters)) {
-               tchain->earliest_time = waiter->wake_up_time;
-               tchain->latest_time = waiter->wake_up_time;
-               TAILQ_INSERT_HEAD(&tchain->waiters, waiter, next);
-               /* Need to turn on the timer interrupt later */
-               return TRUE;
-       }
-       /* If not, either we're first, last, or in the middle.  Reset the interrupt
-        * and adjust the tchain's times accordingly. */
-       if (waiter->wake_up_time < tchain->earliest_time) {
-               tchain->earliest_time = waiter->wake_up_time;
-               TAILQ_INSERT_HEAD(&tchain->waiters, waiter, next);
-               /* Changed the first entry; we'll need to reset the interrupt later */
-               return TRUE;
-       }
-       /* If there is a tie for last, the newer one will really go last.  We need
-        * to handle equality here since the loop later won't catch it. */
-       if (waiter->wake_up_time >= tchain->latest_time) {
-               tchain->latest_time = waiter->wake_up_time;
-               /* Proactively put it at the end if we know we're last */
-               TAILQ_INSERT_TAIL(&tchain->waiters, waiter, next);
-               return FALSE;
-       }
-       /* Insert before the first one you are earlier than.  This won't scale well
-        * (TODO) if we have a lot of inserts.  The proactive insert_tail up above
-        * will help a bit. */
-       TAILQ_FOREACH_SAFE(i, &tchain->waiters, next, temp) {
-               if (waiter->wake_up_time < i->wake_up_time) {
-                       TAILQ_INSERT_BEFORE(i, waiter, next);
-                       return FALSE;
-               }
-       }
-       printf("Could not find a spot for awaiter %p\n", waiter);
-       assert(0);
-}
-
-/* Sets the alarm.  If it is a kthread-style alarm (func == 0), sleep on it
- * later.  This version assumes you have the lock held.  That only makes sense
- * from alarm handlers, which are called with this lock held from IRQ context */
-static void __tc_locked_set_alarm(struct timer_chain *tchain,
-                                  struct alarm_waiter *waiter)
-{      
-       if (__insert_awaiter(tchain, waiter))
-               reset_tchain_interrupt(tchain);
-}
-
-/* Sets the alarm.  Don't call this from an alarm handler, since you already
- * have the lock held.  Call __set_alarm() instead. */
-static void __tc_set_alarm(struct timer_chain *tchain,
-                           struct alarm_waiter *waiter)
-{
-       spin_pdr_lock(&tchain->lock);
-       __set_alarm(waiter);
-       spin_pdr_unlock(&tchain->lock);
-}
-
-/* Helper, rips the waiter from the tchain, knowing that it is on the list.
- * Returns TRUE if the tchain interrupt needs to be reset.  Callers hold the
- * lock. */
-static bool __remove_awaiter(struct timer_chain *tchain,
-                             struct alarm_waiter *waiter)
-{
-       struct alarm_waiter *temp;
-       bool reset_int = FALSE;         /* whether or not to reset the interrupt */
-       /* Need to make sure earliest and latest are set, in case we're mucking with
-        * the first and/or last element of the chain. */
-       if (TAILQ_FIRST(&tchain->waiters) == waiter) {
-               temp = TAILQ_NEXT(waiter, next);
-               tchain->earliest_time = (temp) ? temp->wake_up_time : ALARM_POISON_TIME;
-               reset_int = TRUE;               /* we'll need to reset the timer later */
-       }
-       if (TAILQ_LAST(&tchain->waiters, awaiters_tailq) == waiter) {
-               temp = TAILQ_PREV(waiter, awaiters_tailq, next);
-               tchain->latest_time = (temp) ? temp->wake_up_time : ALARM_POISON_TIME;
-       }
-       TAILQ_REMOVE(&tchain->waiters, waiter, next);
-       return reset_int;
-}
-
-/* Removes waiter from the tchain before it goes off.  Returns TRUE if we
- * disarmed before the alarm went off, FALSE if it already fired.  Also, if
- * FALSE, the alarm has already completed.  Userspace alarms are like kernel IRQ
- * alarms - they run with the tchain lock held, meaning their execution is
- * synchronized with operations like unset. */
-static bool __tc_unset_alarm(struct timer_chain *tchain,
-                             struct alarm_waiter *waiter)
-{
-       spin_pdr_lock(&tchain->lock);
-       if (!waiter->on_tchain) {
-               /* the alarm has already gone off.  its not even on this tchain's list,
-                * though the concurrent change to on_tchain (specifically, the setting
-                * of it to FALSE), happens under the tchain's lock. */
-               spin_pdr_unlock(&tchain->lock);
-               return FALSE;
-       }
-       if (__remove_awaiter(tchain, waiter))
-               reset_tchain_interrupt(tchain);
-       spin_pdr_unlock(&tchain->lock);
-       return TRUE;
-}
-
-/* waiter may be on the tchain, or it might have fired already and be off the
- * tchain.  Either way, this will put the waiter on the list, set to go off at
- * abs_time.  If you know the alarm has fired, don't call this.  Just set the
- * awaiter, and then set_alarm() */
-static void __tc_reset_alarm_abs(struct timer_chain *tchain,
-                                 struct alarm_waiter *waiter, uint64_t abs_time)
-{
-       bool reset_int = FALSE;         /* whether or not to reset the interrupt */
-       spin_pdr_lock(&tchain->lock);
-       /* We only need to remove/unset when the alarm has not fired yet (is still
-        * on the tchain).  If it has fired, it's like a fresh insert */
-       if (waiter->on_tchain)
-               reset_int = __remove_awaiter(tchain, waiter);
-       __set_awaiter_abs(waiter, abs_time);
-       /* regardless, we need to be reinserted */
-       if (__insert_awaiter(tchain, waiter) || reset_int)
-               reset_tchain_interrupt(tchain);
-       spin_pdr_unlock(&tchain->lock);
-}
-
-/* Debug helpers */
-
-void print_chain(struct timer_chain *tchain)
-{
-       struct alarm_waiter *i;
-       spin_pdr_lock(&tchain->lock);
-       printf("Chain %p is%s empty, early: %llu latest: %llu\n", tchain,
-              TAILQ_EMPTY(&tchain->waiters) ? "" : " not",
-              tchain->earliest_time,
-              tchain->latest_time);
-       spin_pdr_unlock(&tchain->lock);
-}
-
-/* "parlib" alarm handlers */
-void alarm_abort_sysc(struct alarm_waiter *awaiter)
-{
-       struct uthread *uth = awaiter->data;
-       assert(uth);
-       if (!uth->sysc) {
-               /* It's possible the sysc hasn't blocked yet or is in the process of
-                * unblocking, or even has returned, but hasn't cancelled the alarm.
-                * regardless, we request a new alarm (the uthread will cancel us one
-                * way or another). */
-               set_awaiter_inc(awaiter, 1000000);
-               __set_alarm(awaiter);
-               return;
-       }
-       sys_abort_sysc(uth->sysc);
-}
diff --git a/user/benchutil/include/benchutil/alarm.h b/user/benchutil/include/benchutil/alarm.h
deleted file mode 100644 (file)
index 5bba12c..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-/* Copyright (c) 2013 The Regents of the University of California
- * Barret Rhoden <brho@cs.berkeley.edu>
- * See LICENSE for details.
- *
- * Userspace alarms.  There are lower level helpers to build your own alarms
- * from the #A device and an alarm service, based off a slimmed down version of
- * the kernel alarms.  Under the hood, the user alarm uses the #A service for
- * the root of the alarm chain.
- *
- * This is (was) hanging out in benchutil so as to not create a dependency from
- * parlib on benchutil (usec2tsc and friends).
- *
- * There's only one timer chain, unlike in the kernel, for the entire process.
- * If you want one-off timers unrelated to the chain (and sent to other vcores),
- * use #A directly.
- *
- * Your handlers will run from vcore context.
- *
- * 1) To set a handler to run on an alarm:
- *     struct alarm_waiter *waiter = malloc(sizeof(struct alarm_waiter));
- *     init_awaiter(waiter, HANDLER);
- *     waiter->data = something;
- *     set_awaiter_rel(waiter, USEC);
- *     set_alarm(waiter);
- * If you want the HANDLER to run again, do this at the end of it:
- *     set_awaiter_rel(waiter, USEC);
- *     __set_alarm(waiter);
- * Do not call set_alarm() from within an alarm handler; you'll deadlock.
- * Don't forget to manage your memory at some (safe) point:
- *     free(waiter); */
-
-#pragma once
-
-#include <parlib/common.h>
-#include <sys/queue.h>
-#include <parlib/spinlock.h>
-#include <parlib/event.h>
-
-__BEGIN_DECLS
-
-/* Low-level alarm interface */
-
-int devalarm_get_fds(int *ctlfd_r, int *timerfd_r, int *alarmid_r);
-int devalarm_set_evq(int timerfd, struct event_queue *ev_q, int alarmid);
-int devalarm_set_time(int timerfd, uint64_t tsc_time);
-int devalarm_get_id(struct event_msg *ev_msg);
-int devalarm_disable(int timerfd);
-
-/* Alarm service */
-
-/* Specifc waiter, per alarm */
-struct alarm_waiter {
-       uint64_t                                        wake_up_time;   /* tsc time */
-       void (*func) (struct alarm_waiter *waiter);
-       void                                            *data;
-       TAILQ_ENTRY(alarm_waiter)       next;
-       bool                                            on_tchain;
-};
-TAILQ_HEAD(awaiters_tailq, alarm_waiter);              /* ideally not a LL */
-
-typedef void (*alarm_handler)(struct alarm_waiter *waiter);
-
-/* Sorted collection of alarms. */
-struct timer_chain {
-       struct spin_pdr_lock            lock;
-       struct awaiters_tailq           waiters;
-       uint64_t                                        earliest_time;
-       uint64_t                                        latest_time;
-       int                                                     ctlfd;
-       int                                                     timerfd;
-       int                                                     alarmid;
-       struct event_queue                      *ev_q;
-};
-
-/* For fresh alarm waiters.  func == 0 for kthreads */
-void init_awaiter(struct alarm_waiter *waiter,
-                  void (*func) (struct alarm_waiter *));
-/* Sets the time an awaiter goes off */
-void set_awaiter_abs_unix(struct alarm_waiter *waiter, uint64_t abs_usec);
-void set_awaiter_rel(struct alarm_waiter *waiter, uint64_t usleep);
-void set_awaiter_inc(struct alarm_waiter *waiter, uint64_t usleep);
-/* Arms/disarms the alarm */
-void __set_alarm(struct alarm_waiter *waiter);
-void set_alarm(struct alarm_waiter *waiter);
-bool unset_alarm(struct alarm_waiter *waiter);
-void reset_alarm_abs(struct alarm_waiter *waiter, uint64_t abs_time);
-
-/* "parlib" alarm handlers */
-void alarm_abort_sysc(struct alarm_waiter *awaiter);
-
-/* Debugging */
-#define ALARM_POISON_TIME 12345
-void print_chain(struct timer_chain *tchain);
-
-__END_DECLS
diff --git a/user/benchutil/include/benchutil/pvcalarm.h b/user/benchutil/include/benchutil/pvcalarm.h
deleted file mode 100644 (file)
index 410e8e5..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-/* Copyright (c) 2014 The Regents of the University of California
- * Kevin Klues <klueska@cs.berkeley.edu>
- * See LICENSE for details. */
-
-#pragma once
-
-#include <stdint.h>
-__BEGIN_DECLS
-
-/* Types of per-vcore alarms that can be set */
-enum {
-       /* This is a real-time alarm that does not take into account time that a
-        * vcore spends offline not doing work. It is like the posix ITIMER_REAL
-        * but for vcores. */
-       PVCALARM_REAL,
-       /* This is a profiling alarm that only accounts for time that a vcore
-        * spends online doing useful work. It is like the posix ITIMER_PROF but
-        * for vcores. */
-       PVCALARM_PROF
-};
-
-/* Enable the per-vcore calarm service according to one of the policies listed
- * above.  Every interval usecs the provided callback will be called on each
- * active vcore according to that policy. */
-int enable_pvcalarms(int policy, uint64_t interval, void (*callback) (void));
-
-/* Disable the currently active per-vcore alarm service */
-int disable_pvcalarms();
-
-__END_DECLS
diff --git a/user/benchutil/include/benchutil/vcore_tick.h b/user/benchutil/include/benchutil/vcore_tick.h
deleted file mode 100644 (file)
index 8c1f4ed..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-/* Copyright (c) 2016 Google Inc.
- * Barret Rhoden <brho@cs.berkeley.edu>
- * See LICENSE for details.
- *
- * Vcore timer ticks.
- *
- * Each vcore can independently operate timer ticks, based in virtual time (the
- * time a vcore is actually online).  When the tick expires, the vcore will
- * receive an IPI/notification, not any event via handle_events().  These ticks
- * need to be polled by the 2LS.
- *
- * E.g. to set and use a 10ms tick:
- *
- *             vcore_tick_enable(10000);
- *
- * In the 2LS sched_entry():
- *
- *             if (vcore_tick_poll())
- *                     time_is_up_do_something();
- *
- * You can change the period on the fly, and it will kick in after the next
- * tick.  You can also attempt to enable or disable the alarm as many times as
- * you want.  For instance:
- *
- *             vcore_tick_enable(10000);
- *             vcore_tick_enable(10000);
- *             vcore_tick_enable(10000);
- *
- * will only set one alarm.  The latter two calls just set the period to 10000
- * 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
-
-#include <ros/event.h>
-#include <sys/types.h>
-
-__BEGIN_DECLS
-
-void vcore_tick_enable(uint64_t period_usec);
-void vcore_tick_disable(void);
-int vcore_tick_poll(void);
-
-__END_DECLS
diff --git a/user/benchutil/pvcalarm.c b/user/benchutil/pvcalarm.c
deleted file mode 100644 (file)
index 087ab9b..0000000
+++ /dev/null
@@ -1,278 +0,0 @@
-/* Copyright (c) 2014 The Regents of the University of California
- * Kevin Klues <klueska@cs.berkeley.edu>
- * See LICENSE for details. */
-
-#include <stdint.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <errno.h>
-#include <parlib/parlib.h>
-#include <parlib/vcore.h>
-#include <parlib/event.h>
-#include <parlib/spinlock.h>
-#include <parlib/arch/atomic.h>
-#include <parlib/arch/bitmask.h>
-#include <sys/queue.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <benchutil/pvcalarm.h>
-#include <benchutil/alarm.h>
-
-/* Different states for enabling/disabling the per-vcore alarms. */
-enum {
-       S_ENABLING,
-       S_ENABLED,
-       S_DISABLING,
-       S_DISABLED,
-};
-
-/* The data associated with each per-vcore alarm that needs to be tracked by
- * each vcore. It is ultimately stored in an __thread variable. */
-struct pvcalarm_data {
-       int ctlfd;
-       int timerfd;
-       int alarmid;
-       uint64_t start_uptime;
-};
-
-/* The global state of the pvcalarm service itself */
-struct pvcalarm {
-       uint64_t interval;
-       void (*callback) (void);
-
-       atomic_t state;
-       int busy_count;
-       handle_event_t handler;
-       struct pvcalarm_data *data;
-};
-
-/* The only state we need to make sure is set for the global alarm service is
- * to make sure it s in the disabled state at bootup */
-static struct pvcalarm global_pvcalarm = { .state = (void*)S_DISABLED };
-
-/* Helper functions */
-static void init_pvcalarm(struct pvcalarm_data *pvcalarm_data, int vcoreid);
-static void handle_pvcalarm(struct event_msg *ev_msg, unsigned int ev_type,
-                            void *data);
-static void handle_alarm_real(struct event_msg *ev_msg, unsigned int ev_type,
-                              void *data);
-static void handle_alarm_prof(struct event_msg *ev_msg, unsigned int ev_type,
-                              void *data);
-
-/* Initialize the pvcalarm service. Only call this function once */
-static void init_global_pvcalarm(void *arg)
-{
-       global_pvcalarm.interval = 0;
-       global_pvcalarm.callback = NULL;
-       global_pvcalarm.busy_count = 0;
-       global_pvcalarm.handler = NULL;
-
-       /* Preemptively setup timers for all possible vcores */
-       global_pvcalarm.data = malloc(max_vcores() * sizeof(struct pvcalarm_data));
-       for (int i=0; i<max_vcores(); i++) {
-               init_pvcalarm(&global_pvcalarm.data[i], i);
-       }
-}
-
-/* Run the pvc alarm associated with pvcalarm_data for the given amount of
- * time */
-static void run_pvcalarm(struct pvcalarm_data *pvcalarm_data, uint64_t offset)
-{
-       if (devalarm_set_time(pvcalarm_data->timerfd, read_tsc() + offset)) {
-               perror("Useralarm: Failed to set timer");
-               return;
-       }
-}
-
-/* Run the pvc alarm associated with pvcalarm_data for the given amount of
- * time. Also mark the start time of the alarm so we can use it for accounting
- * later. */
-static void start_pvcalarm(struct pvcalarm_data *pvcalarm_data, uint64_t offset)
-{
-       pvcalarm_data->start_uptime = vcore_account_uptime_ticks(vcore_id());
-       run_pvcalarm(pvcalarm_data, offset);
-}
-
-/* Stop the pvc alarm associated with pvcalarm_data */
-static void stop_pvcalarm(struct pvcalarm_data *pvcalarm_data)
-{
-       if (devalarm_disable(pvcalarm_data->timerfd)) {
-               printf("Useralarm: unable to disarm alarm!\n");
-               return;
-       }
-}
-
-/* Enable the per-vcore alarm service according to one of the policies listed
- * above.  Every interval usecs the provided callback will be called on each
- * active vcore according to that policy. */
-int enable_pvcalarms(int method, uint64_t interval, void (*callback) (void))
-{
-       static parlib_once_t once = PARLIB_ONCE_INIT;
-
-       assert(!in_vcore_context());
-       if (method != PVCALARM_REAL && method != PVCALARM_PROF)
-               return EINVAL;
-
-       if (atomic_cas(&global_pvcalarm.state, S_ENABLED, S_ENABLED))
-               return EALREADY;
-
-       if (!atomic_cas(&global_pvcalarm.state, S_DISABLED, S_ENABLING))
-               return EBUSY;
-
-       parlib_run_once(&once, init_global_pvcalarm, NULL);
-
-       global_pvcalarm.interval = usec2tsc(interval);
-       global_pvcalarm.callback = callback;
-       global_pvcalarm.busy_count = 0;
-       switch (method) {
-               case PVCALARM_REAL:
-                       global_pvcalarm.handler = handle_alarm_real;
-                       break;
-               case PVCALARM_PROF:
-                       global_pvcalarm.handler = handle_alarm_prof;
-                       break;
-       }
-
-       /* Start the timer on all vcores to go off after interval usecs */
-       for (int i=0; i<max_vcores(); i++) {
-               start_pvcalarm(&global_pvcalarm.data[i], global_pvcalarm.interval);
-       }
-
-       atomic_set(&global_pvcalarm.state, S_ENABLED);
-       return 0;
-}
-
-/* Disable the currently active per-vcore alarm service */
-int disable_pvcalarms()
-{
-       assert(!in_vcore_context());
-       if (atomic_cas(&global_pvcalarm.state, S_DISABLED, S_DISABLED))
-               return EALREADY;
-
-       if (!atomic_cas(&global_pvcalarm.state, S_ENABLED, S_DISABLING))
-               return EBUSY;
-
-       /* We loop here to let any vcores currently running code associated with
-        * the pvcalarms to finish what they are doing before we disable the
-        * pvcalarm service.  Since we ensure that this function is only called
-        * from non-vcore context, this is OK. */
-       while(global_pvcalarm.busy_count != 0)
-               cpu_relax();
-       
-       global_pvcalarm.interval = 0;
-       global_pvcalarm.callback = NULL;
-       global_pvcalarm.handler = NULL;
-
-       /* Stop the timer on all vcores */
-       for (int i=0; i<max_vcores(); i++)
-               stop_pvcalarm(&global_pvcalarm.data[i]);
-
-       atomic_set(&global_pvcalarm.state, S_DISABLED);
-       return 0;
-}
-
-/* Initialize a specific pvcalarm.  This happens once per vcore as it comes
- * online and the pvcalarm service is active */
-static void init_pvcalarm(struct pvcalarm_data *pvcalarm_data, int vcoreid)
-{
-       int ctlfd, timerfd, alarmid, ev_flags;
-       struct event_queue *ev_q;
-
-       if (devalarm_get_fds(&ctlfd, &timerfd, &alarmid)) {
-               perror("Pvcalarm: alarm setup");
-               return;
-       }
-       register_ev_handler(EV_ALARM, handle_pvcalarm, 0);
-       ev_flags = EVENT_IPI | EVENT_VCORE_PRIVATE;
-       ev_q = get_eventq_vcpd(vcoreid, ev_flags);
-       if (!ev_q) {
-               perror("Pvcalarm: Failed ev_q");
-               return;
-       }
-       ev_q->ev_vcore = vcoreid;
-       ev_q->ev_flags = ev_flags;
-       if (devalarm_set_evq(timerfd, ev_q, alarmid)) {
-               perror("Pvcalarm: Failed to set evq");
-               return;
-       }
-       /* now the alarm is all set, just need to write the timer whenever we want
-        * it to go off. */
-       pvcalarm_data->alarmid = alarmid;
-       pvcalarm_data->ctlfd = ctlfd;
-       pvcalarm_data->timerfd = timerfd;
-}
-
-/* TODO: implement a way to completely remove each per-vcore alarm and
- * deregister it from the #alarm device */
-
-/* A preamble function to run anytime we are about to do anything on behalf of
- * the pvcalarms while in vcore context.  This preamble is necessary to ensure
- * we maintain proper invariants when enabling and disabling the pvcalarm
- * service in a running application. */
-static inline bool __vcore_preamble()
-{
-       int state;
-       assert(in_vcore_context());
-       __sync_fetch_and_add(&global_pvcalarm.busy_count, 1);
-       cmb();  /* order the state read after the incref.  __sync provides cpu mb */
-       state = atomic_read(&global_pvcalarm.state);
-       if (state == S_DISABLED || state == S_DISABLING)
-               goto disabled;
-       return true;
-disabled:
-       __sync_fetch_and_add(&global_pvcalarm.busy_count, -1);
-       return false;
-}
-
-/* The counterpart to the __vcore_preamble() function */
-static inline void __vcore_postamble()
-{
-       __sync_fetch_and_add(&global_pvcalarm.busy_count, -1);
-}
-
-/* The global handler function.  It simply calls the proper underlying handler
- * function depending on whether the service is set for the REAL or PERF
- * policy. */
-static void handle_pvcalarm(struct event_msg *ev_msg, unsigned int ev_type,
-                            void *data)
-{
-       struct pvcalarm_data *pvcalarm_data = &global_pvcalarm.data[vcore_id()];
-
-       if (devalarm_get_id(ev_msg) != pvcalarm_data->alarmid)
-               return;
-       if (!__vcore_preamble()) return;
-       global_pvcalarm.handler(ev_msg, ev_type, data);
-       __vcore_postamble();
-}
-
-/* The pvcalarm handler for the REAL policy.  Simply call the registered
- * callback and restart the interval alarm. */
-static void handle_alarm_real(struct event_msg *ev_msg, unsigned int ev_type,
-                              void *data)
-{
-       global_pvcalarm.callback();
-       start_pvcalarm(&global_pvcalarm.data[vcore_id()], global_pvcalarm.interval);
-}
-
-/* The pvcalarm handler for the PROF policy.  Account for any time the vcore
- * has been offline.  Only when the uptime since the last interval is equal to
- * the interval time do we run the callback function.  Otherwise we restart the
- * alarm to make up the difference. */
-static void handle_alarm_prof(struct event_msg *ev_msg, unsigned int ev_type,
-                              void *data)
-{ 
-       int vcoreid = vcore_id();
-       struct pvcalarm_data *pvcalarm_data = &global_pvcalarm.data[vcoreid];
-       uint32_t uptime = vcore_account_uptime_ticks(vcoreid);
-       uint64_t diff = uptime - pvcalarm_data->start_uptime;
-
-       if (diff < global_pvcalarm.interval) {
-               uint64_t remaining = global_pvcalarm.interval - diff;
-               run_pvcalarm(pvcalarm_data, remaining);
-       } else {
-               global_pvcalarm.callback();
-               start_pvcalarm(pvcalarm_data, global_pvcalarm.interval);
-       }
-}
-
diff --git a/user/benchutil/vcore_tick.c b/user/benchutil/vcore_tick.c
deleted file mode 100644 (file)
index ebbd908..0000000
+++ /dev/null
@@ -1,175 +0,0 @@
-/* Copyright (c) 2016 Google Inc.
- * Barret Rhoden <brho@cs.berkeley.edu>
- * See LICENSE for details.
- *
- * 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>
-#include <benchutil/alarm.h>
-#include <benchutil/vcore_tick.h>
-
-/* TODO: if we use some other form of per-vcore memory, we can also have a
- * per-vcore init function that we run before the VC spools up, removing the
- * need to check for PREINIT. */
-
-enum {
-       VC_TICK_PREINIT = 0,
-       VC_TICK_ENABLED = 1,
-       VC_TICK_DISABLED = 2,
-};
-
-struct vcore_tick {
-       int                                                     state;
-       int                                                     ctl_fd;
-       int                                                     timer_fd;
-       uint64_t                                        next_deadline;
-       uint64_t                                        period_ticks;
-       struct event_queue                      *ev_q;
-};
-
-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)
-{
-       int ret;
-
-       ret = devalarm_get_fds(&vc_tick->ctl_fd, &vc_tick->timer_fd, 0);
-       assert(!ret);
-       /* We want an IPI and a bit set in the bitmask.  But no wakeups, in case
-        * we're offline. */
-       vc_tick->ev_q = get_eventq(EV_MBOX_BITMAP);
-       assert(vc_tick->ev_q);
-       vc_tick->ev_q->ev_flags = EVENT_IPI;
-       vc_tick->ev_q->ev_vcore = vcore_id();
-       ret = devalarm_set_evq(vc_tick->timer_fd, vc_tick->ev_q, 0);
-       assert(!ret);
-       vc_tick->state = VC_TICK_DISABLED;
-}
-
-static void __vcore_tick_start(struct vcore_tick *vc_tick, uint64_t from_now)
-{
-       int ret;
-
-       ret = devalarm_set_time(vc_tick->timer_fd, read_tsc() + from_now);
-       assert(!ret);
-}
-
-/* Starts a timer tick for this vcore, in virtual time (time the vcore is
- * actually online).  You can call this repeatedly, even if the timer is already
- * 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;
-
-       uth_disable_notifs();
-       vc_tick = get_my_tick();
-       if (vc_tick->state == VC_TICK_PREINIT)
-               vcore_tick_init(vc_tick);
-
-       vc_tick->period_ticks = usec2tsc(period_usec);
-       if (vc_tick->state == VC_TICK_DISABLED) {
-               vc_tick->next_deadline = vcore_account_uptime_ticks(vcore_id()) +
-                                        vc_tick->period_ticks;
-               __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;
-       int ret;
-
-       uth_disable_notifs();
-       vc_tick = get_my_tick();
-       if (vc_tick->state == VC_TICK_PREINIT)
-               vcore_tick_init(vc_tick);
-
-       if (vc_tick->state == VC_TICK_ENABLED) {
-               ret = devalarm_disable(vc_tick->timer_fd);
-               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
- * for not yet otherwise.  Either way, it will ensure that the underlying alarm
- * is still turned on. */
-int vcore_tick_poll(void)
-{
-       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);
-
-       evbm = &vc_tick->ev_q->ev_mbox->evbm;
-       if (!GET_BITMASK_BIT(evbm->bitmap, EV_ALARM)) {
-               /* It might be possible that the virtual time has passed, but the alarm
-                * hasn't arrived yet.
-                *
-                * We assume that if the bit is not set and the tick is enabled that
-                * the kernel still has an alarm set for us.  It is possible for the bit
-                * to be set more than expected (disable an alarm, but fail to cancel
-                * the alarm before it goes off, then enable it, and then we'll have the
-                * bit set before the alarm expired).  However, it is not possible that
-                * the bit is clear and there is no alarm pending at this point.  This
-                * is because the only time we clear the bit is below, and then right
-                * after that we set an alarm. (The bit is also clear at init time, and
-                * we start the alarm when we enable the tick).
-                *
-                * Anyway, the alarm should be arriving shortly.  In this case, as in
-                * the case where the bit gets set right after we check, we missed
-                * 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) */
-       CLR_BITMASK_BIT(evbm->bitmap, EV_ALARM);
-       /* As mentioned above, it is possible to still have an active alarm in the
-        * kernel.  We can still set a new time for the alarm, and it will just
-        * update the kernel's awaiter.  And if that alarm has fired, then we'll
-        * just have a spurious setting of the bit.  This does not affect our return
-        * value, which is based on virtual time, not alarm resets. */
-       virtual_now = vcore_account_uptime_ticks(vcore_id());
-       /* It's possible that we've fallen multiple ticks behind virtual now.
-        * In that case, we'll just jump ahead a bit */
-       while (vc_tick->next_deadline <= virtual_now) {
-               ret++;
-               vc_tick->next_deadline += vc_tick->period_ticks;
-       }
-       /* There's a slight chance we miss an alarm if the period is very small.
-        * virtual_now is a little old.  If the period is so small that this is a
-        * problem and if we updated virtual now in the while loop, then we'd also
-        * 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;
-}
diff --git a/user/parlib/alarm.c b/user/parlib/alarm.c
new file mode 100644 (file)
index 0000000..22f08e8
--- /dev/null
@@ -0,0 +1,484 @@
+/* Copyright (c) 2013 The Regents of the University of California
+ * Barret Rhoden <brho@cs.berkeley.edu>
+ * See LICENSE for details.
+ *
+ * Userspace alarms.  There are lower level helpers to build your own alarms
+ * from the #alarm device and an alarm service, based off a slimmed down version
+ * of the kernel alarms.  Under the hood, the user alarm uses the #alarm service
+ * for the root of the alarm chain.
+ *
+ * There's only one timer chain, unlike in the kernel, for the entire process.
+ * If you want one-off timers unrelated to the chain (and sent to other vcores),
+ * use #alarm directly.
+ *
+ * Your handlers will run from vcore context.
+ *
+ * Code differences from the kernel (for future porting):
+ * - init_alarm_service, run as a constructor
+ * - set_alarm() and friends are __tc_set_alarm(), passing global_tchain.
+ * - reset_tchain_interrupt() uses #alarm
+ * - removed anything related to semaphores or kthreads
+ * - spinlocks -> spin_pdr_locks
+ * - ev_q wrappers for converting #alarm events to __triggers
+ * - printks, and other minor stuff. */
+
+#include <sys/queue.h>
+#include <sys/time.h>
+#include <parlib/alarm.h>
+#include <stdio.h>
+#include <parlib/assert.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <parlib/parlib.h>
+#include <parlib/event.h>
+#include <parlib/uthread.h>
+#include <parlib/spinlock.h>
+#include <parlib/timing.h>
+#include <sys/plan9_helpers.h>
+#include <sys/fork_cb.h>
+
+/* Helper to get your own alarm.   If you don't care about a return value, pass
+ * 0 and it'll be ignored.  The alarm is built, but has no evq or timer set. */
+int devalarm_get_fds(int *ctlfd_r, int *timerfd_r, int *alarmid_r)
+{
+       int ctlfd, timerfd, alarmid, ret;
+       char buf[20];
+       char path[32];
+
+       ctlfd = open("#alarm/clone", O_RDWR | O_CLOEXEC);
+       if (ctlfd < 0)
+               return -1;
+       ret = read(ctlfd, buf, sizeof(buf) - 1);
+       if (ret <= 0)
+               return -1;
+       buf[ret] = 0;
+       alarmid = atoi(buf);
+       snprintf(path, sizeof(path), "#alarm/a%s/timer", buf);
+       timerfd = open(path, O_RDWR | O_CLOEXEC);
+       if (timerfd < 0)
+               return -1;
+       if (ctlfd_r)
+               *ctlfd_r = ctlfd;
+       else
+               close(ctlfd);
+       if (timerfd_r)
+               *timerfd_r = timerfd;
+       else
+               close(timerfd);
+       if (alarmid_r)
+               *alarmid_r = alarmid;
+       return 0;
+}
+
+int devalarm_set_evq(int timerfd, struct event_queue *ev_q, int alarmid)
+{
+       struct fd_tap_req tap_req = {0};
+
+       tap_req.fd = timerfd;
+       tap_req.cmd = FDTAP_CMD_ADD;
+       tap_req.filter = FDTAP_FILT_WRITTEN;
+       tap_req.ev_id = EV_ALARM;
+       tap_req.ev_q = ev_q;
+       tap_req.data = (void*)(long)alarmid;
+       if (sys_tap_fds(&tap_req, 1) != 1)
+               return -1;
+       return 0;
+}
+
+int devalarm_set_time(int timerfd, uint64_t tsc_time)
+{
+       return write_hex_to_fd(timerfd, tsc_time);
+}
+
+int devalarm_get_id(struct event_msg *ev_msg)
+{
+       if (!ev_msg)
+               return -1;
+       return (int)(long)ev_msg->ev_arg3;
+}
+
+int devalarm_disable(int timerfd)
+{
+       return write_hex_to_fd(timerfd, 0);
+}
+
+/* Helpers, basically renamed kernel interfaces, with the *tchain. */
+static void __tc_locked_set_alarm(struct timer_chain *tchain,
+                                  struct alarm_waiter *waiter);
+static void __tc_set_alarm(struct timer_chain *tchain,
+                           struct alarm_waiter *waiter);
+static bool __tc_unset_alarm(struct timer_chain *tchain,
+                             struct alarm_waiter *waiter);
+static void __tc_reset_alarm_abs(struct timer_chain *tchain,
+                                 struct alarm_waiter *waiter,
+                                 uint64_t abs_time);
+static void handle_user_alarm(struct event_msg *ev_msg, unsigned int ev_type,
+                              void *data);
+
+/* One chain to rule them all. */
+struct timer_chain global_tchain;
+
+/* Helper, resets the earliest/latest times, based on the elements of the list.
+ * If the list is empty, we set the times to be the 12345 poison time.  Since
+ * the list is empty, the alarm shouldn't be going off. */
+static void reset_tchain_times(struct timer_chain *tchain)
+{
+       if (TAILQ_EMPTY(&tchain->waiters)) {
+               tchain->earliest_time = ALARM_POISON_TIME;
+               tchain->latest_time = ALARM_POISON_TIME;
+       } else {
+               tchain->earliest_time = TAILQ_FIRST(&tchain->waiters)->wake_up_time;
+               tchain->latest_time =
+                       TAILQ_LAST(&tchain->waiters, awaiters_tailq)->wake_up_time;
+       }
+}
+
+static void devalarm_forked(void)
+{
+       /* We need to poison the FDs too, in case the child attempts to use the
+        * alarms.  It'd be chaos if they read/wrote to an arbitrary open FD. */
+       close(global_tchain.ctlfd);
+       global_tchain.ctlfd = -42;
+       close(global_tchain.timerfd);
+       global_tchain.timerfd = -42;
+}
+
+static void __attribute__((constructor)) init_alarm_service(void)
+{
+       int ctlfd, timerfd, alarmid;
+       struct event_queue *ev_q;
+       static struct fork_cb devalarm_fork_cb = {.func = devalarm_forked};
+
+       /* Sets up timer chain (only one chain per process) */
+       spin_pdr_init(&global_tchain.lock);
+       TAILQ_INIT(&global_tchain.waiters);
+       reset_tchain_times(&global_tchain);
+
+       if (devalarm_get_fds(&ctlfd, &timerfd, &alarmid)) {
+               perror("Useralarm: devalarm_get_fds");
+               return;
+       }
+       /* Since we're doing SPAM_PUBLIC later, we actually don't need a big ev_q.
+        * But someone might copy/paste this and change a flag. */
+       register_ev_handler(EV_ALARM, handle_user_alarm, 0);
+       if (!(ev_q = get_eventq(EV_MBOX_UCQ))) {
+               perror("Useralarm: Failed ev_q");
+               return;
+       }
+       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 (probably with SPAM_INDIR too) instead of SPAM_PUBLIC. */
+       ev_q->ev_flags = EVENT_IPI | EVENT_SPAM_PUBLIC | EVENT_WAKEUP;
+       if (devalarm_set_evq(timerfd, ev_q, alarmid)) {
+               perror("set_alarm_evq");
+               return;
+       }
+       /* now the alarm is all set, just need to write the timer whenever we want
+        * it to go off. */
+       global_tchain.alarmid = alarmid;
+       global_tchain.ctlfd = ctlfd;
+       global_tchain.timerfd = timerfd;
+       global_tchain.ev_q = ev_q;      /* mostly for debugging */
+       register_fork_cb(&devalarm_fork_cb);
+}
+
+/* Initializes a new awaiter. */
+void init_awaiter(struct alarm_waiter *waiter,
+                  void (*func) (struct alarm_waiter *awaiter))
+{
+       waiter->wake_up_time = ALARM_POISON_TIME;
+       assert(func);
+       waiter->func = func;
+       waiter->on_tchain = FALSE;
+}
+
+/* Give this the absolute time.  For now, abs_time is the TSC time that you want
+ * the alarm to go off. */
+static void __set_awaiter_abs(struct alarm_waiter *waiter, uint64_t abs_time)
+{
+       waiter->wake_up_time = abs_time;
+}
+
+/* Give this the absolute unix time (in microseconds) that you want the alarm
+ * to go off. */
+void set_awaiter_abs_unix(struct alarm_waiter *waiter, uint64_t abs_usec)
+{
+       __set_awaiter_abs(waiter, epoch_nsec_to_tsc(abs_usec * 1000));
+}
+
+/* Give this a relative time from now, in microseconds.  This might be easier to
+ * use than dealing with the TSC. */
+void set_awaiter_rel(struct alarm_waiter *waiter, uint64_t usleep)
+{
+       uint64_t now, then;
+       now = read_tsc();
+       then = now + usec2tsc(usleep);
+       /* This will go off if we wrap-around the TSC.  It'll never happen for legit
+        * values, but this might catch some bugs with large usleeps. */
+       assert(now <= then);
+       __set_awaiter_abs(waiter, then);
+}
+
+/* Increment the timer that was already set, so that it goes off usleep usec
+ * from the previous tick.  This is different than 'rel' in that it doesn't care
+ * about when 'now' is. */
+void set_awaiter_inc(struct alarm_waiter *waiter, uint64_t usleep)
+{
+       assert(waiter->wake_up_time != ALARM_POISON_TIME);
+       waiter->wake_up_time += usec2tsc(usleep);
+}
+
+/* User interface to the global tchain */
+void __set_alarm(struct alarm_waiter *waiter)
+{
+       __tc_locked_set_alarm(&global_tchain, waiter);
+}
+
+void set_alarm(struct alarm_waiter *waiter)
+{
+       __tc_set_alarm(&global_tchain, waiter);
+}
+
+bool unset_alarm(struct alarm_waiter *waiter)
+{
+       return __tc_unset_alarm(&global_tchain, waiter);
+}
+
+void reset_alarm_abs(struct alarm_waiter *waiter, uint64_t abs_time)
+{
+       __tc_reset_alarm_abs(&global_tchain, waiter, abs_time);
+}
+
+/* Helper, makes sure the kernel alarm is turned on at the right time. */
+static void reset_tchain_interrupt(struct timer_chain *tchain)
+{
+       if (TAILQ_EMPTY(&tchain->waiters)) {
+               /* Turn it off */
+               printd("Turning alarm off\n");
+               if (devalarm_disable(tchain->timerfd)) {
+                       printf("Useralarm: unable to disarm alarm!\n");
+                       return;
+               }
+       } else {
+               /* Make sure it is on and set to the earliest time */
+               assert(tchain->earliest_time != ALARM_POISON_TIME);
+               /* TODO: check for times in the past or very close to now */
+               printd("Turning alarm on for %llu\n", tchain->earliest_time);
+               if (devalarm_set_time(tchain->timerfd, tchain->earliest_time)) {
+                       perror("Useralarm: Failed to set timer");
+                       return;
+               }
+       }
+}
+
+/* When an awaiter's time has come, this gets called. */
+static void wake_awaiter(struct alarm_waiter *waiter)
+{
+       waiter->on_tchain = FALSE;
+       cmb();  /* enforce the on_tchain write before the handlers */
+       waiter->func(waiter);
+}
+
+/* This is called when the kernel alarm triggers a tchain, and needs to wake up
+ * everyone whose time is up.  Called from vcore context. */
+static void __trigger_tchain(struct timer_chain *tchain)
+{
+       struct alarm_waiter *i, *temp;
+       uint64_t now = read_tsc();
+       bool changed_list = FALSE;
+       spin_pdr_lock(&tchain->lock);
+       TAILQ_FOREACH_SAFE(i, &tchain->waiters, next, temp) {
+               printd("Trying to wake up %p who is due at %llu and now is %llu\n",
+                      i, i->wake_up_time, now);
+               /* TODO: Could also do something in cases where we're close to now */
+               if (i->wake_up_time <= now) {
+                       changed_list = TRUE;
+                       TAILQ_REMOVE(&tchain->waiters, i, next);
+                       /* Don't touch the waiter after waking it, since it could be in use
+                        * on another core (and the waiter can be clobbered as the kthread
+                        * unwinds its stack).  Or it could be kfreed */
+                       wake_awaiter(i);
+               } else {
+                       break;
+               }
+       }
+       if (changed_list) {
+               reset_tchain_times(tchain);
+       }
+       /* Need to reset the interrupt no matter what */
+       reset_tchain_interrupt(tchain);
+       spin_pdr_unlock(&tchain->lock);
+}
+
+static void handle_user_alarm(struct event_msg *ev_msg, unsigned int ev_type,
+                              void *data)
+{
+       assert(ev_type == EV_ALARM);
+       if (devalarm_get_id(ev_msg) == global_tchain.alarmid)
+               __trigger_tchain(&global_tchain);
+}
+
+/* Helper, inserts the waiter into the tchain, returning TRUE if we still need
+ * to reset the tchain interrupt.  Caller holds the lock. */
+static bool __insert_awaiter(struct timer_chain *tchain,
+                             struct alarm_waiter *waiter)
+{
+       struct alarm_waiter *i, *temp;
+       /* This will fail if you don't set a time */
+       assert(waiter->wake_up_time != ALARM_POISON_TIME);
+       waiter->on_tchain = TRUE;
+       /* Either the list is empty, or not. */
+       if (TAILQ_EMPTY(&tchain->waiters)) {
+               tchain->earliest_time = waiter->wake_up_time;
+               tchain->latest_time = waiter->wake_up_time;
+               TAILQ_INSERT_HEAD(&tchain->waiters, waiter, next);
+               /* Need to turn on the timer interrupt later */
+               return TRUE;
+       }
+       /* If not, either we're first, last, or in the middle.  Reset the interrupt
+        * and adjust the tchain's times accordingly. */
+       if (waiter->wake_up_time < tchain->earliest_time) {
+               tchain->earliest_time = waiter->wake_up_time;
+               TAILQ_INSERT_HEAD(&tchain->waiters, waiter, next);
+               /* Changed the first entry; we'll need to reset the interrupt later */
+               return TRUE;
+       }
+       /* If there is a tie for last, the newer one will really go last.  We need
+        * to handle equality here since the loop later won't catch it. */
+       if (waiter->wake_up_time >= tchain->latest_time) {
+               tchain->latest_time = waiter->wake_up_time;
+               /* Proactively put it at the end if we know we're last */
+               TAILQ_INSERT_TAIL(&tchain->waiters, waiter, next);
+               return FALSE;
+       }
+       /* Insert before the first one you are earlier than.  This won't scale well
+        * (TODO) if we have a lot of inserts.  The proactive insert_tail up above
+        * will help a bit. */
+       TAILQ_FOREACH_SAFE(i, &tchain->waiters, next, temp) {
+               if (waiter->wake_up_time < i->wake_up_time) {
+                       TAILQ_INSERT_BEFORE(i, waiter, next);
+                       return FALSE;
+               }
+       }
+       printf("Could not find a spot for awaiter %p\n", waiter);
+       assert(0);
+}
+
+/* Sets the alarm.  If it is a kthread-style alarm (func == 0), sleep on it
+ * later.  This version assumes you have the lock held.  That only makes sense
+ * from alarm handlers, which are called with this lock held from IRQ context */
+static void __tc_locked_set_alarm(struct timer_chain *tchain,
+                                  struct alarm_waiter *waiter)
+{
+       if (__insert_awaiter(tchain, waiter))
+               reset_tchain_interrupt(tchain);
+}
+
+/* Sets the alarm.  Don't call this from an alarm handler, since you already
+ * have the lock held.  Call __set_alarm() instead. */
+static void __tc_set_alarm(struct timer_chain *tchain,
+                           struct alarm_waiter *waiter)
+{
+       spin_pdr_lock(&tchain->lock);
+       __set_alarm(waiter);
+       spin_pdr_unlock(&tchain->lock);
+}
+
+/* Helper, rips the waiter from the tchain, knowing that it is on the list.
+ * Returns TRUE if the tchain interrupt needs to be reset.  Callers hold the
+ * lock. */
+static bool __remove_awaiter(struct timer_chain *tchain,
+                             struct alarm_waiter *waiter)
+{
+       struct alarm_waiter *temp;
+       bool reset_int = FALSE;         /* whether or not to reset the interrupt */
+       /* Need to make sure earliest and latest are set, in case we're mucking with
+        * the first and/or last element of the chain. */
+       if (TAILQ_FIRST(&tchain->waiters) == waiter) {
+               temp = TAILQ_NEXT(waiter, next);
+               tchain->earliest_time = (temp) ? temp->wake_up_time : ALARM_POISON_TIME;
+               reset_int = TRUE;               /* we'll need to reset the timer later */
+       }
+       if (TAILQ_LAST(&tchain->waiters, awaiters_tailq) == waiter) {
+               temp = TAILQ_PREV(waiter, awaiters_tailq, next);
+               tchain->latest_time = (temp) ? temp->wake_up_time : ALARM_POISON_TIME;
+       }
+       TAILQ_REMOVE(&tchain->waiters, waiter, next);
+       return reset_int;
+}
+
+/* Removes waiter from the tchain before it goes off.  Returns TRUE if we
+ * disarmed before the alarm went off, FALSE if it already fired.  Also, if
+ * FALSE, the alarm has already completed.  Userspace alarms are like kernel IRQ
+ * alarms - they run with the tchain lock held, meaning their execution is
+ * synchronized with operations like unset. */
+static bool __tc_unset_alarm(struct timer_chain *tchain,
+                             struct alarm_waiter *waiter)
+{
+       spin_pdr_lock(&tchain->lock);
+       if (!waiter->on_tchain) {
+               /* the alarm has already gone off.  its not even on this tchain's list,
+                * though the concurrent change to on_tchain (specifically, the setting
+                * of it to FALSE), happens under the tchain's lock. */
+               spin_pdr_unlock(&tchain->lock);
+               return FALSE;
+       }
+       if (__remove_awaiter(tchain, waiter))
+               reset_tchain_interrupt(tchain);
+       spin_pdr_unlock(&tchain->lock);
+       return TRUE;
+}
+
+/* waiter may be on the tchain, or it might have fired already and be off the
+ * tchain.  Either way, this will put the waiter on the list, set to go off at
+ * abs_time.  If you know the alarm has fired, don't call this.  Just set the
+ * awaiter, and then set_alarm() */
+static void __tc_reset_alarm_abs(struct timer_chain *tchain,
+                                 struct alarm_waiter *waiter, uint64_t abs_time)
+{
+       bool reset_int = FALSE;         /* whether or not to reset the interrupt */
+       spin_pdr_lock(&tchain->lock);
+       /* We only need to remove/unset when the alarm has not fired yet (is still
+        * on the tchain).  If it has fired, it's like a fresh insert */
+       if (waiter->on_tchain)
+               reset_int = __remove_awaiter(tchain, waiter);
+       __set_awaiter_abs(waiter, abs_time);
+       /* regardless, we need to be reinserted */
+       if (__insert_awaiter(tchain, waiter) || reset_int)
+               reset_tchain_interrupt(tchain);
+       spin_pdr_unlock(&tchain->lock);
+}
+
+/* Debug helpers */
+
+void print_chain(struct timer_chain *tchain)
+{
+       struct alarm_waiter *i;
+       spin_pdr_lock(&tchain->lock);
+       printf("Chain %p is%s empty, early: %llu latest: %llu\n", tchain,
+              TAILQ_EMPTY(&tchain->waiters) ? "" : " not",
+              tchain->earliest_time,
+              tchain->latest_time);
+       spin_pdr_unlock(&tchain->lock);
+}
+
+/* "parlib" alarm handlers */
+void alarm_abort_sysc(struct alarm_waiter *awaiter)
+{
+       struct uthread *uth = awaiter->data;
+       assert(uth);
+       if (!uth->sysc) {
+               /* It's possible the sysc hasn't blocked yet or is in the process of
+                * unblocking, or even has returned, but hasn't cancelled the alarm.
+                * regardless, we request a new alarm (the uthread will cancel us one
+                * way or another). */
+               set_awaiter_inc(awaiter, 1000000);
+               __set_alarm(awaiter);
+               return;
+       }
+       sys_abort_sysc(uth->sysc);
+}
diff --git a/user/parlib/include/parlib/alarm.h b/user/parlib/include/parlib/alarm.h
new file mode 100644 (file)
index 0000000..682cffa
--- /dev/null
@@ -0,0 +1,93 @@
+/* Copyright (c) 2013 The Regents of the University of California
+ * Barret Rhoden <brho@cs.berkeley.edu>
+ * See LICENSE for details.
+ *
+ * Userspace alarms.  There are lower level helpers to build your own alarms
+ * from the #A device and an alarm service, based off a slimmed down version of
+ * the kernel alarms.  Under the hood, the user alarm uses the #A service for
+ * the root of the alarm chain.
+ *
+ * There's only one timer chain, unlike in the kernel, for the entire process.
+ * If you want one-off timers unrelated to the chain (and sent to other vcores),
+ * use #A directly.
+ *
+ * Your handlers will run from vcore context.
+ *
+ * 1) To set a handler to run on an alarm:
+ *     struct alarm_waiter *waiter = malloc(sizeof(struct alarm_waiter));
+ *     init_awaiter(waiter, HANDLER);
+ *     waiter->data = something;
+ *     set_awaiter_rel(waiter, USEC);
+ *     set_alarm(waiter);
+ * If you want the HANDLER to run again, do this at the end of it:
+ *     set_awaiter_rel(waiter, USEC);
+ *     __set_alarm(waiter);
+ * Do not call set_alarm() from within an alarm handler; you'll deadlock.
+ * Don't forget to manage your memory at some (safe) point:
+ *     free(waiter); */
+
+#pragma once
+
+#include <parlib/common.h>
+#include <sys/queue.h>
+#include <parlib/spinlock.h>
+#include <parlib/event.h>
+
+__BEGIN_DECLS
+
+/* Low-level alarm interface */
+
+int devalarm_get_fds(int *ctlfd_r, int *timerfd_r, int *alarmid_r);
+int devalarm_set_evq(int timerfd, struct event_queue *ev_q, int alarmid);
+int devalarm_set_time(int timerfd, uint64_t tsc_time);
+int devalarm_get_id(struct event_msg *ev_msg);
+int devalarm_disable(int timerfd);
+
+/* Alarm service */
+
+/* Specifc waiter, per alarm */
+struct alarm_waiter {
+       uint64_t                                        wake_up_time;   /* tsc time */
+       void (*func) (struct alarm_waiter *waiter);
+       void                                            *data;
+       TAILQ_ENTRY(alarm_waiter)       next;
+       bool                                            on_tchain;
+};
+TAILQ_HEAD(awaiters_tailq, alarm_waiter);              /* ideally not a LL */
+
+typedef void (*alarm_handler)(struct alarm_waiter *waiter);
+
+/* Sorted collection of alarms. */
+struct timer_chain {
+       struct spin_pdr_lock            lock;
+       struct awaiters_tailq           waiters;
+       uint64_t                                        earliest_time;
+       uint64_t                                        latest_time;
+       int                                                     ctlfd;
+       int                                                     timerfd;
+       int                                                     alarmid;
+       struct event_queue                      *ev_q;
+};
+
+/* For fresh alarm waiters.  func == 0 for kthreads */
+void init_awaiter(struct alarm_waiter *waiter,
+                  void (*func) (struct alarm_waiter *));
+/* Sets the time an awaiter goes off */
+void set_awaiter_abs_unix(struct alarm_waiter *waiter, uint64_t abs_usec);
+void set_awaiter_rel(struct alarm_waiter *waiter, uint64_t usleep);
+void set_awaiter_inc(struct alarm_waiter *waiter, uint64_t usleep);
+
+/* Arms/disarms the alarm */
+void __set_alarm(struct alarm_waiter *waiter);
+void set_alarm(struct alarm_waiter *waiter);
+bool unset_alarm(struct alarm_waiter *waiter);
+void reset_alarm_abs(struct alarm_waiter *waiter, uint64_t abs_time);
+
+/* "parlib" alarm handlers */
+void alarm_abort_sysc(struct alarm_waiter *awaiter);
+
+/* Debugging */
+#define ALARM_POISON_TIME 12345
+void print_chain(struct timer_chain *tchain);
+
+__END_DECLS
diff --git a/user/parlib/include/parlib/pvcalarm.h b/user/parlib/include/parlib/pvcalarm.h
new file mode 100644 (file)
index 0000000..909b0e4
--- /dev/null
@@ -0,0 +1,31 @@
+/* Copyright (c) 2014 The Regents of the University of California
+ * Kevin Klues <klueska@cs.berkeley.edu>
+ * See LICENSE for details. */
+
+#pragma once
+
+#include <stdint.h>
+
+__BEGIN_DECLS
+
+/* Types of per-vcore alarms that can be set */
+enum {
+       /* This is a real-time alarm that does not take into account time that a
+        * vcore spends offline not doing work. It is like the posix ITIMER_REAL
+        * but for vcores. */
+       PVCALARM_REAL,
+       /* This is a profiling alarm that only accounts for time that a vcore
+        * spends online doing useful work. It is like the posix ITIMER_PROF but
+        * for vcores. */
+       PVCALARM_PROF
+};
+
+/* Enable the per-vcore calarm service according to one of the policies listed
+ * above.  Every interval usecs the provided callback will be called on each
+ * active vcore according to that policy. */
+int enable_pvcalarms(int policy, uint64_t interval, void (*callback) (void));
+
+/* Disable the currently active per-vcore alarm service */
+int disable_pvcalarms();
+
+__END_DECLS
diff --git a/user/parlib/include/parlib/vcore_tick.h b/user/parlib/include/parlib/vcore_tick.h
new file mode 100644 (file)
index 0000000..8c1f4ed
--- /dev/null
@@ -0,0 +1,47 @@
+/* Copyright (c) 2016 Google Inc.
+ * Barret Rhoden <brho@cs.berkeley.edu>
+ * See LICENSE for details.
+ *
+ * Vcore timer ticks.
+ *
+ * Each vcore can independently operate timer ticks, based in virtual time (the
+ * time a vcore is actually online).  When the tick expires, the vcore will
+ * receive an IPI/notification, not any event via handle_events().  These ticks
+ * need to be polled by the 2LS.
+ *
+ * E.g. to set and use a 10ms tick:
+ *
+ *             vcore_tick_enable(10000);
+ *
+ * In the 2LS sched_entry():
+ *
+ *             if (vcore_tick_poll())
+ *                     time_is_up_do_something();
+ *
+ * You can change the period on the fly, and it will kick in after the next
+ * tick.  You can also attempt to enable or disable the alarm as many times as
+ * you want.  For instance:
+ *
+ *             vcore_tick_enable(10000);
+ *             vcore_tick_enable(10000);
+ *             vcore_tick_enable(10000);
+ *
+ * will only set one alarm.  The latter two calls just set the period to 10000
+ * 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
+
+#include <ros/event.h>
+#include <sys/types.h>
+
+__BEGIN_DECLS
+
+void vcore_tick_enable(uint64_t period_usec);
+void vcore_tick_disable(void);
+int vcore_tick_poll(void);
+
+__END_DECLS
diff --git a/user/parlib/pvcalarm.c b/user/parlib/pvcalarm.c
new file mode 100644 (file)
index 0000000..95f9fdc
--- /dev/null
@@ -0,0 +1,277 @@
+/* Copyright (c) 2014 The Regents of the University of California
+ * Kevin Klues <klueska@cs.berkeley.edu>
+ * See LICENSE for details. */
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <parlib/parlib.h>
+#include <parlib/vcore.h>
+#include <parlib/event.h>
+#include <parlib/spinlock.h>
+#include <parlib/arch/atomic.h>
+#include <parlib/arch/bitmask.h>
+#include <sys/queue.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <parlib/pvcalarm.h>
+#include <parlib/alarm.h>
+
+/* Different states for enabling/disabling the per-vcore alarms. */
+enum {
+       S_ENABLING,
+       S_ENABLED,
+       S_DISABLING,
+       S_DISABLED,
+};
+
+/* The data associated with each per-vcore alarm that needs to be tracked by
+ * each vcore. It is ultimately stored in an __thread variable. */
+struct pvcalarm_data {
+       int ctlfd;
+       int timerfd;
+       int alarmid;
+       uint64_t start_uptime;
+};
+
+/* The global state of the pvcalarm service itself */
+struct pvcalarm {
+       uint64_t interval;
+       void (*callback) (void);
+
+       atomic_t state;
+       int busy_count;
+       handle_event_t handler;
+       struct pvcalarm_data *data;
+};
+
+/* The only state we need to make sure is set for the global alarm service is
+ * to make sure it s in the disabled state at bootup */
+static struct pvcalarm global_pvcalarm = { .state = (void*)S_DISABLED };
+
+/* Helper functions */
+static void init_pvcalarm(struct pvcalarm_data *pvcalarm_data, int vcoreid);
+static void handle_pvcalarm(struct event_msg *ev_msg, unsigned int ev_type,
+                            void *data);
+static void handle_alarm_real(struct event_msg *ev_msg, unsigned int ev_type,
+                              void *data);
+static void handle_alarm_prof(struct event_msg *ev_msg, unsigned int ev_type,
+                              void *data);
+
+/* Initialize the pvcalarm service. Only call this function once */
+static void init_global_pvcalarm(void *arg)
+{
+       global_pvcalarm.interval = 0;
+       global_pvcalarm.callback = NULL;
+       global_pvcalarm.busy_count = 0;
+       global_pvcalarm.handler = NULL;
+
+       /* Preemptively setup timers for all possible vcores */
+       global_pvcalarm.data = malloc(max_vcores() * sizeof(struct pvcalarm_data));
+       for (int i=0; i<max_vcores(); i++) {
+               init_pvcalarm(&global_pvcalarm.data[i], i);
+       }
+}
+
+/* Run the pvc alarm associated with pvcalarm_data for the given amount of
+ * time */
+static void run_pvcalarm(struct pvcalarm_data *pvcalarm_data, uint64_t offset)
+{
+       if (devalarm_set_time(pvcalarm_data->timerfd, read_tsc() + offset)) {
+               perror("Useralarm: Failed to set timer");
+               return;
+       }
+}
+
+/* Run the pvc alarm associated with pvcalarm_data for the given amount of
+ * time. Also mark the start time of the alarm so we can use it for accounting
+ * later. */
+static void start_pvcalarm(struct pvcalarm_data *pvcalarm_data, uint64_t offset)
+{
+       pvcalarm_data->start_uptime = vcore_account_uptime_ticks(vcore_id());
+       run_pvcalarm(pvcalarm_data, offset);
+}
+
+/* Stop the pvc alarm associated with pvcalarm_data */
+static void stop_pvcalarm(struct pvcalarm_data *pvcalarm_data)
+{
+       if (devalarm_disable(pvcalarm_data->timerfd)) {
+               printf("Useralarm: unable to disarm alarm!\n");
+               return;
+       }
+}
+
+/* Enable the per-vcore alarm service according to one of the policies listed
+ * above.  Every interval usecs the provided callback will be called on each
+ * active vcore according to that policy. */
+int enable_pvcalarms(int method, uint64_t interval, void (*callback) (void))
+{
+       static parlib_once_t once = PARLIB_ONCE_INIT;
+
+       assert(!in_vcore_context());
+       if (method != PVCALARM_REAL && method != PVCALARM_PROF)
+               return EINVAL;
+
+       if (atomic_cas(&global_pvcalarm.state, S_ENABLED, S_ENABLED))
+               return EALREADY;
+
+       if (!atomic_cas(&global_pvcalarm.state, S_DISABLED, S_ENABLING))
+               return EBUSY;
+
+       parlib_run_once(&once, init_global_pvcalarm, NULL);
+
+       global_pvcalarm.interval = usec2tsc(interval);
+       global_pvcalarm.callback = callback;
+       global_pvcalarm.busy_count = 0;
+       switch (method) {
+               case PVCALARM_REAL:
+                       global_pvcalarm.handler = handle_alarm_real;
+                       break;
+               case PVCALARM_PROF:
+                       global_pvcalarm.handler = handle_alarm_prof;
+                       break;
+       }
+
+       /* Start the timer on all vcores to go off after interval usecs */
+       for (int i=0; i<max_vcores(); i++) {
+               start_pvcalarm(&global_pvcalarm.data[i], global_pvcalarm.interval);
+       }
+
+       atomic_set(&global_pvcalarm.state, S_ENABLED);
+       return 0;
+}
+
+/* Disable the currently active per-vcore alarm service */
+int disable_pvcalarms()
+{
+       assert(!in_vcore_context());
+       if (atomic_cas(&global_pvcalarm.state, S_DISABLED, S_DISABLED))
+               return EALREADY;
+
+       if (!atomic_cas(&global_pvcalarm.state, S_ENABLED, S_DISABLING))
+               return EBUSY;
+
+       /* We loop here to let any vcores currently running code associated with
+        * the pvcalarms to finish what they are doing before we disable the
+        * pvcalarm service.  Since we ensure that this function is only called
+        * from non-vcore context, this is OK. */
+       while(global_pvcalarm.busy_count != 0)
+               cpu_relax();
+
+       global_pvcalarm.interval = 0;
+       global_pvcalarm.callback = NULL;
+       global_pvcalarm.handler = NULL;
+
+       /* Stop the timer on all vcores */
+       for (int i=0; i<max_vcores(); i++)
+               stop_pvcalarm(&global_pvcalarm.data[i]);
+
+       atomic_set(&global_pvcalarm.state, S_DISABLED);
+       return 0;
+}
+
+/* Initialize a specific pvcalarm.  This happens once per vcore as it comes
+ * online and the pvcalarm service is active */
+static void init_pvcalarm(struct pvcalarm_data *pvcalarm_data, int vcoreid)
+{
+       int ctlfd, timerfd, alarmid, ev_flags;
+       struct event_queue *ev_q;
+
+       if (devalarm_get_fds(&ctlfd, &timerfd, &alarmid)) {
+               perror("Pvcalarm: alarm setup");
+               return;
+       }
+       register_ev_handler(EV_ALARM, handle_pvcalarm, 0);
+       ev_flags = EVENT_IPI | EVENT_VCORE_PRIVATE;
+       ev_q = get_eventq_vcpd(vcoreid, ev_flags);
+       if (!ev_q) {
+               perror("Pvcalarm: Failed ev_q");
+               return;
+       }
+       ev_q->ev_vcore = vcoreid;
+       ev_q->ev_flags = ev_flags;
+       if (devalarm_set_evq(timerfd, ev_q, alarmid)) {
+               perror("Pvcalarm: Failed to set evq");
+               return;
+       }
+       /* now the alarm is all set, just need to write the timer whenever we want
+        * it to go off. */
+       pvcalarm_data->alarmid = alarmid;
+       pvcalarm_data->ctlfd = ctlfd;
+       pvcalarm_data->timerfd = timerfd;
+}
+
+/* TODO: implement a way to completely remove each per-vcore alarm and
+ * deregister it from the #alarm device */
+
+/* A preamble function to run anytime we are about to do anything on behalf of
+ * the pvcalarms while in vcore context.  This preamble is necessary to ensure
+ * we maintain proper invariants when enabling and disabling the pvcalarm
+ * service in a running application. */
+static inline bool __vcore_preamble()
+{
+       int state;
+       assert(in_vcore_context());
+       __sync_fetch_and_add(&global_pvcalarm.busy_count, 1);
+       cmb();  /* order the state read after the incref.  __sync provides cpu mb */
+       state = atomic_read(&global_pvcalarm.state);
+       if (state == S_DISABLED || state == S_DISABLING)
+               goto disabled;
+       return true;
+disabled:
+       __sync_fetch_and_add(&global_pvcalarm.busy_count, -1);
+       return false;
+}
+
+/* The counterpart to the __vcore_preamble() function */
+static inline void __vcore_postamble()
+{
+       __sync_fetch_and_add(&global_pvcalarm.busy_count, -1);
+}
+
+/* The global handler function.  It simply calls the proper underlying handler
+ * function depending on whether the service is set for the REAL or PERF
+ * policy. */
+static void handle_pvcalarm(struct event_msg *ev_msg, unsigned int ev_type,
+                            void *data)
+{
+       struct pvcalarm_data *pvcalarm_data = &global_pvcalarm.data[vcore_id()];
+
+       if (devalarm_get_id(ev_msg) != pvcalarm_data->alarmid)
+               return;
+       if (!__vcore_preamble()) return;
+       global_pvcalarm.handler(ev_msg, ev_type, data);
+       __vcore_postamble();
+}
+
+/* The pvcalarm handler for the REAL policy.  Simply call the registered
+ * callback and restart the interval alarm. */
+static void handle_alarm_real(struct event_msg *ev_msg, unsigned int ev_type,
+                              void *data)
+{
+       global_pvcalarm.callback();
+       start_pvcalarm(&global_pvcalarm.data[vcore_id()], global_pvcalarm.interval);
+}
+
+/* The pvcalarm handler for the PROF policy.  Account for any time the vcore
+ * has been offline.  Only when the uptime since the last interval is equal to
+ * the interval time do we run the callback function.  Otherwise we restart the
+ * alarm to make up the difference. */
+static void handle_alarm_prof(struct event_msg *ev_msg, unsigned int ev_type,
+                              void *data)
+{
+       int vcoreid = vcore_id();
+       struct pvcalarm_data *pvcalarm_data = &global_pvcalarm.data[vcoreid];
+       uint32_t uptime = vcore_account_uptime_ticks(vcoreid);
+       uint64_t diff = uptime - pvcalarm_data->start_uptime;
+
+       if (diff < global_pvcalarm.interval) {
+               uint64_t remaining = global_pvcalarm.interval - diff;
+               run_pvcalarm(pvcalarm_data, remaining);
+       } else {
+               global_pvcalarm.callback();
+               start_pvcalarm(pvcalarm_data, global_pvcalarm.interval);
+       }
+}
diff --git a/user/parlib/vcore_tick.c b/user/parlib/vcore_tick.c
new file mode 100644 (file)
index 0000000..d19ab95
--- /dev/null
@@ -0,0 +1,175 @@
+/* Copyright (c) 2016 Google Inc.
+ * Barret Rhoden <brho@cs.berkeley.edu>
+ * See LICENSE for details.
+ *
+ * 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>
+#include <parlib/alarm.h>
+#include <parlib/vcore_tick.h>
+
+/* TODO: if we use some other form of per-vcore memory, we can also have a
+ * per-vcore init function that we run before the VC spools up, removing the
+ * need to check for PREINIT. */
+
+enum {
+       VC_TICK_PREINIT = 0,
+       VC_TICK_ENABLED = 1,
+       VC_TICK_DISABLED = 2,
+};
+
+struct vcore_tick {
+       int                                                     state;
+       int                                                     ctl_fd;
+       int                                                     timer_fd;
+       uint64_t                                        next_deadline;
+       uint64_t                                        period_ticks;
+       struct event_queue                      *ev_q;
+};
+
+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)
+{
+       int ret;
+
+       ret = devalarm_get_fds(&vc_tick->ctl_fd, &vc_tick->timer_fd, 0);
+       assert(!ret);
+       /* We want an IPI and a bit set in the bitmask.  But no wakeups, in case
+        * we're offline. */
+       vc_tick->ev_q = get_eventq(EV_MBOX_BITMAP);
+       assert(vc_tick->ev_q);
+       vc_tick->ev_q->ev_flags = EVENT_IPI;
+       vc_tick->ev_q->ev_vcore = vcore_id();
+       ret = devalarm_set_evq(vc_tick->timer_fd, vc_tick->ev_q, 0);
+       assert(!ret);
+       vc_tick->state = VC_TICK_DISABLED;
+}
+
+static void __vcore_tick_start(struct vcore_tick *vc_tick, uint64_t from_now)
+{
+       int ret;
+
+       ret = devalarm_set_time(vc_tick->timer_fd, read_tsc() + from_now);
+       assert(!ret);
+}
+
+/* Starts a timer tick for this vcore, in virtual time (time the vcore is
+ * actually online).  You can call this repeatedly, even if the timer is already
+ * 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;
+
+       uth_disable_notifs();
+       vc_tick = get_my_tick();
+       if (vc_tick->state == VC_TICK_PREINIT)
+               vcore_tick_init(vc_tick);
+
+       vc_tick->period_ticks = usec2tsc(period_usec);
+       if (vc_tick->state == VC_TICK_DISABLED) {
+               vc_tick->next_deadline = vcore_account_uptime_ticks(vcore_id()) +
+                                        vc_tick->period_ticks;
+               __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;
+       int ret;
+
+       uth_disable_notifs();
+       vc_tick = get_my_tick();
+       if (vc_tick->state == VC_TICK_PREINIT)
+               vcore_tick_init(vc_tick);
+
+       if (vc_tick->state == VC_TICK_ENABLED) {
+               ret = devalarm_disable(vc_tick->timer_fd);
+               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
+ * for not yet otherwise.  Either way, it will ensure that the underlying alarm
+ * is still turned on. */
+int vcore_tick_poll(void)
+{
+       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);
+
+       evbm = &vc_tick->ev_q->ev_mbox->evbm;
+       if (!GET_BITMASK_BIT(evbm->bitmap, EV_ALARM)) {
+               /* It might be possible that the virtual time has passed, but the alarm
+                * hasn't arrived yet.
+                *
+                * We assume that if the bit is not set and the tick is enabled that
+                * the kernel still has an alarm set for us.  It is possible for the bit
+                * to be set more than expected (disable an alarm, but fail to cancel
+                * the alarm before it goes off, then enable it, and then we'll have the
+                * bit set before the alarm expired).  However, it is not possible that
+                * the bit is clear and there is no alarm pending at this point.  This
+                * is because the only time we clear the bit is below, and then right
+                * after that we set an alarm. (The bit is also clear at init time, and
+                * we start the alarm when we enable the tick).
+                *
+                * Anyway, the alarm should be arriving shortly.  In this case, as in
+                * the case where the bit gets set right after we check, we missed
+                * 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) */
+       CLR_BITMASK_BIT(evbm->bitmap, EV_ALARM);
+       /* As mentioned above, it is possible to still have an active alarm in the
+        * kernel.  We can still set a new time for the alarm, and it will just
+        * update the kernel's awaiter.  And if that alarm has fired, then we'll
+        * just have a spurious setting of the bit.  This does not affect our return
+        * value, which is based on virtual time, not alarm resets. */
+       virtual_now = vcore_account_uptime_ticks(vcore_id());
+       /* It's possible that we've fallen multiple ticks behind virtual now.
+        * In that case, we'll just jump ahead a bit */
+       while (vc_tick->next_deadline <= virtual_now) {
+               ret++;
+               vc_tick->next_deadline += vc_tick->period_ticks;
+       }
+       /* There's a slight chance we miss an alarm if the period is very small.
+        * virtual_now is a little old.  If the period is so small that this is a
+        * problem and if we updated virtual now in the while loop, then we'd also
+        * 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;
+}
index d82dfc3..b2436e9 100644 (file)
@@ -8,7 +8,7 @@
 #include <errno.h>
 #include <parlib/slab.h>
 #include <parlib/mcs.h>
-#include <benchutil/alarm.h>
+#include <parlib/alarm.h>
 
 static inline int futex_wake(int *uaddr, int count);
 static inline int futex_wait(int *uaddr, int val, uint64_t ms_timeout);
index d45c054..e4873d5 100644 (file)
@@ -3,7 +3,7 @@
  * See LICENSE for details. */
 
 #include <pthread.h>
-#include <benchutil/pvcalarm.h>
+#include <parlib/pvcalarm.h>
 
 void pvcalarm_callback(void)
 {
index 083e01a..61a8e22 100644 (file)
@@ -2,7 +2,7 @@
 #include <semaphore.h>
 #include <parlib/mcs.h>
 #include <stdio.h>
-#include <benchutil/alarm.h>
+#include <parlib/alarm.h>
 #include <errno.h>
 
 int sem_init (sem_t *__sem, int __pshared, unsigned int __value)
index 18553f9..b364ad1 100644 (file)
@@ -21,7 +21,7 @@
 #include <sys/queue.h>
 #include <pthread.h>
 #include <parlib/mcs.h>
-#include <benchutil/alarm.h>
+#include <parlib/alarm.h>
 
 __BEGIN_DECLS
 
index bfb5950..61c1f90 100644 (file)
@@ -1,5 +1,5 @@
 #include <utest/utest.h>
-#include <benchutil/alarm.h>
+#include <parlib/alarm.h>
 
 TEST_SUITE("ALARMS");
 
index b310e02..bc61048 100644 (file)
@@ -1,6 +1,6 @@
 #include <utest/utest.h>
 #include <pthread.h>
-#include <benchutil/pvcalarm.h>
+#include <parlib/pvcalarm.h>
 
 TEST_SUITE("PVCALARMS");
 
index eeebc65..95bed94 100644 (file)
@@ -14,7 +14,7 @@
 #include <parlib/ucq.h>
 #include <parlib/arch/trap.h>
 #include <parlib/ros_debug.h>
-#include <benchutil/vcore_tick.h>
+#include <parlib/vcore_tick.h>
 
 int vmm_sched_period_usec = 1000;