rendez: tell callers whether or not we timedout
authorBarret Rhoden <brho@cs.berkeley.edu>
Mon, 2 Mar 2020 17:26:10 +0000 (12:26 -0500)
committerBarret Rhoden <brho@cs.berkeley.edu>
Wed, 1 Apr 2020 22:27:54 +0000 (18:27 -0400)
Previously, you couldn't tell if you timed out or not.  It might not be
that useful, given the inherent raciness with these operations, but I
used this briefly in some testing code.

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

index e1d5720..9885bb5 100644 (file)
@@ -26,7 +26,9 @@
  * - Wakers should set the condition, then trigger the wakeup to ensure the
  *   sleeper has awakened.  (internal locks provide the needed barriers).
  * - Timeout sleep is like regular sleep, with the addition that it will return
- *   after some milliseconds, regardless of the condition.
+ *   after some milliseconds, regardless of the condition.  Returns 'false' if
+ *   it timedout and wasn't rendezvoused.  Note that even if we timed out, the
+ *   condition may be true, due to races.
  * - The only locking/protection is done internally.  In plan9, they expect to
  *   only have one sleeper and one waker.  So your code around the rendez needs
  *   to take that into account.  The old plan9 code should already do this.
@@ -49,7 +51,7 @@ typedef int (*rendez_cond_t)(void *arg);
 
 void rendez_init(struct rendez *rv);
 void rendez_sleep(struct rendez *rv, int (*cond)(void*), void *arg);
-void rendez_sleep_timeout(struct rendez *rv, int (*cond)(void*), void *arg,
+bool rendez_sleep_timeout(struct rendez *rv, int (*cond)(void*), void *arg,
                           uint64_t usec);
 bool rendez_wakeup(struct rendez *rv);
 void rendez_debug_waiter(struct alarm_waiter *awaiter);
index f046556..cb3e81a 100644 (file)
@@ -80,23 +80,24 @@ void rendez_debug_waiter(struct alarm_waiter *awaiter)
 }
 
 /* Like sleep, but it will timeout in 'usec' microseconds. */
-void rendez_sleep_timeout(struct rendez *rv, int (*cond)(void*), void *arg,
+bool rendez_sleep_timeout(struct rendez *rv, int (*cond)(void*), void *arg,
                           uint64_t usec)
 {
        int8_t irq_state = 0;
        struct alarm_waiter awaiter;
        struct cv_lookup_elm cle;
        struct timer_chain *pcpui_tchain = &per_cpu_info[core_id()].tchain;
+       bool ret;
 
        assert(can_block(this_pcpui_ptr()));
        if (!usec)
-               return;
+               return false;
        /* Doing this cond check early, but then unlocking again.  Mostly just
         * to avoid weird issues with the CV lock and the alarm tchain lock. */
        cv_lock_irqsave(&rv->cv, &irq_state);
        if (cond(arg)) {
                cv_unlock_irqsave(&rv->cv, &irq_state);
-               return;
+               return true;
        }
        cv_unlock_irqsave(&rv->cv, &irq_state);
        /* The handler will call rendez_wake, but won't mess with the condition
@@ -115,7 +116,15 @@ 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) && !alarm_expired(&awaiter)) {
+       while (1) {
+               if (alarm_expired(&awaiter)) {
+                       ret = false;
+                       break;
+               }
+               if (cond(arg)) {
+                       ret = true;
+                       break;
+               }
                if (should_abort(&cle)) {
                        cv_unlock_irqsave(&rv->cv, &irq_state);
                        unset_alarm(pcpui_tchain, &awaiter);
@@ -130,6 +139,7 @@ void rendez_sleep_timeout(struct rendez *rv, int (*cond)(void*), void *arg,
        /* Turn off our alarm.  If it already fired, this is a no-op.  Note this
         * could be cross-core. */
        unset_alarm(pcpui_tchain, &awaiter);
+       return ret;
 }
 
 /* plan9 rendez returned a pointer to the proc woken up.  we return "true" if we