alarm: Add a alarm_expired()
authorBarret Rhoden <brho@cs.berkeley.edu>
Tue, 13 Nov 2018 02:18:57 +0000 (21:18 -0500)
committerBarret Rhoden <brho@cs.berkeley.edu>
Fri, 14 Dec 2018 22:23:48 +0000 (17:23 -0500)
The rendez code was looking at on_tchain to determine if it had expired
or not.  It is possible for the alarm to have expired even though the
handler hasn't run yet.  If an alarm runs as an RKM, its time might
have come, but it is still on the tchain.  In these cases, we want to
timeout the rendez instead of waiting for the alarm service.

Note that this is safe in regards to the alarm's memory.  I was briefly
worried that we're breaking out of the rendez loop before the alarm
handler runs.  But we do that all the time, such as when a condition
fires, and we handle it by calling unset_alarm().

I noticed this when trying to debug a potential livelock.  We might be
able to go back to on_tchain or something else if that read_tsc() is a
problem.  In that case, we'll just change the helper.

Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
kern/include/alarm.h
kern/src/rendez.c

index 97933fc..c9f6197 100644 (file)
@@ -119,6 +119,11 @@ void __trigger_tchain(struct timer_chain *tchain, struct hw_trapframe *hw_tf);
 /* Sets the timer chain interrupt according to the next timer in the chain. */
 void set_pcpu_alarm_interrupt(struct timer_chain *tchain);
 
+static inline bool alarm_expired(struct alarm_waiter *awaiter)
+{
+       return awaiter->wake_up_time <= read_tsc();
+}
+
 /* Debugging */
 #define ALARM_POISON_TIME 12345                                /* could use some work */
 void print_chain(struct timer_chain *tchain);
index 4313c9a..215e85f 100644 (file)
@@ -97,7 +97,7 @@ void rendez_sleep_timeout(struct rendez *rv, int (*cond)(void*), void *arg,
         * condition (and we should exit), other alarms with different timeouts (and
         * we should go back to sleep), etc.  Note it is possible for our alarm to
         * fire immediately upon setting it: before we even cv_lock. */
-       while (!cond(arg) && awaiter.on_tchain) {
+       while (!cond(arg) && !alarm_expired(&awaiter)) {
                if (should_abort(&cle)) {
                        cv_unlock_irqsave(&rv->cv, &irq_state);
                        unset_alarm(pcpui_tchain, &awaiter);