Set tchain earliest/latest on any removal
authorBarret Rhoden <brho@cs.berkeley.edu>
Fri, 15 Jun 2018 21:27:05 +0000 (17:27 -0400)
committerBarret Rhoden <brho@cs.berkeley.edu>
Fri, 15 Jun 2018 21:27:05 +0000 (17:27 -0400)
Alarm handlers can put themselves back on the tchain during their handler.
The logic for that involves the earliest/latest times.  Those times should
change since the old awaiter (which is running) was yanked off.

I didn't have any actual problems with this, but it popped up as a
potential issue.

Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
kern/src/alarm.c
tests/alarm.c
user/parlib/alarm.c

index 6ca48ac..52e21d3 100644 (file)
@@ -156,7 +156,7 @@ void __trigger_tchain(struct timer_chain *tchain, struct hw_trapframe *hw_tf)
 {
        struct alarm_waiter *i, *temp;
        uint64_t now = read_tsc();
-       bool changed_list = FALSE;
+
        /* why do we disable irqs here?  the lock is irqsave, but we (think we) know
         * the timer IRQ for this tchain won't fire again.  disabling irqs is nice
         * for the lock debugger.  i don't want to disable the debugger completely,
@@ -168,9 +168,11 @@ void __trigger_tchain(struct timer_chain *tchain, struct hw_trapframe *hw_tf)
                       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;
                        i->on_tchain = FALSE;
                        TAILQ_REMOVE(&tchain->waiters, i, next);
+                       /* Need to reset after each removal, in case the handler sets the
+                        * alarm again and the earliest/latest times are wrong. */
+                       reset_tchain_times(tchain);
                        cmb();  /* enforce waking after removal */
                        /* 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
@@ -180,9 +182,6 @@ void __trigger_tchain(struct timer_chain *tchain, struct hw_trapframe *hw_tf)
                        break;
                }
        }
-       if (changed_list) {
-               reset_tchain_times(tchain);
-       }
        /* Need to reset the interrupt no matter what */
        reset_tchain_interrupt(tchain);
        spin_unlock_irqsave(&tchain->lock);
index ce72778..62b1d4d 100644 (file)
@@ -5,7 +5,7 @@
  * alarm: basic functionality test for the #alarm device */
 
 #include <stdlib.h>
-#include <stdio.h>
+#include <parlib/stdio.h>
 #include <parlib/parlib.h>
 #include <unistd.h>
 #include <parlib/event.h>
index e790b96..4878bf4 100644 (file)
@@ -288,16 +288,18 @@ 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;
                        i->on_tchain = FALSE;
                        TAILQ_REMOVE(&tchain->waiters, i, next);
+                       /* Need to reset after each removal, in case the handler sets the
+                        * alarm again and the earliest/latest times are wrong. */
+                       reset_tchain_times(tchain);
                        cmb();  /* enforce waking after removal */
                        /* 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
@@ -307,9 +309,6 @@ static void __trigger_tchain(struct timer_chain *tchain)
                        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);