Kernel alarm helpers
authorBarret Rhoden <brho@cs.berkeley.edu>
Wed, 10 Dec 2014 06:24:04 +0000 (22:24 -0800)
committerBarret Rhoden <brho@cs.berkeley.edu>
Wed, 10 Dec 2014 06:55:08 +0000 (22:55 -0800)
Reset and unset are idempotent, making them much more useful than just
set_alarm.  I might get rid of set_alarm and just have them all be reset
or something.

And if there's an ABS version, you probably want a REL version too.

And the __ locked versions are for use in IRQ handlers (though not for
RKM handlers).  Be careful!

kern/include/alarm.h
kern/src/alarm.c

index 752775f..0fb2bf7 100644 (file)
@@ -99,12 +99,19 @@ void init_awaiter_irq(struct alarm_waiter *waiter,
 void set_awaiter_abs(struct alarm_waiter *waiter, uint64_t abs_time);
 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 */
+/* Arms/disarms the alarm.  Hold the lock when calling __methods.  */
 void __set_alarm(struct timer_chain *tchain, struct alarm_waiter *waiter);
 void set_alarm(struct timer_chain *tchain, struct alarm_waiter *waiter);
 bool unset_alarm(struct timer_chain *tchain, struct alarm_waiter *waiter);
+void __reset_alarm_abs(struct timer_chain *tchain, struct alarm_waiter *waiter,
+                       uint64_t abs_time);
+void __reset_alarm_rel(struct timer_chain *tchain, struct alarm_waiter *waiter,
+                       uint64_t usleep);
 void reset_alarm_abs(struct timer_chain *tchain, struct alarm_waiter *waiter,
                      uint64_t abs_time);
+void reset_alarm_rel(struct timer_chain *tchain, struct alarm_waiter *waiter,
+                     uint64_t usleep);
+
 /* Blocks on the alarm waiter */
 int sleep_on_awaiter(struct alarm_waiter *waiter);
 /* Interrupt handlers need to call this.  Don't call it directly. */
index 81891ba..ec1dc04 100644 (file)
@@ -292,11 +292,10 @@ bool unset_alarm(struct timer_chain *tchain, struct alarm_waiter *waiter)
  * 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() */
-void reset_alarm_abs(struct timer_chain *tchain, struct alarm_waiter *waiter,
-                     uint64_t abs_time)
+void __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_lock_irqsave(&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)
@@ -305,6 +304,31 @@ void reset_alarm_abs(struct timer_chain *tchain, struct alarm_waiter *waiter,
        /* regardless, we need to be reinserted */
        if (__insert_awaiter(tchain, waiter) || reset_int)
                reset_tchain_interrupt(tchain);
+}
+
+void __reset_alarm_rel(struct timer_chain *tchain, struct alarm_waiter *waiter,
+                       uint64_t usleep)
+{
+       uint64_t now, then;
+       now = read_tsc();
+       then = now + usec2tsc(usleep);
+       assert(now <= then);
+       __reset_alarm_abs(tchain, waiter, then);
+}
+
+void reset_alarm_abs(struct timer_chain *tchain, struct alarm_waiter *waiter,
+                     uint64_t abs_time)
+{
+       spin_lock_irqsave(&tchain->lock);
+       __reset_alarm_abs(tchain, waiter, abs_time);
+       spin_unlock_irqsave(&tchain->lock);
+}
+
+void reset_alarm_rel(struct timer_chain *tchain, struct alarm_waiter *waiter,
+                     uint64_t usleep)
+{
+       spin_lock_irqsave(&tchain->lock);
+       __reset_alarm_rel(tchain, waiter, usleep);
        spin_unlock_irqsave(&tchain->lock);
 }