rendez: tell callers whether or not we timedout
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>
diff --git a/kern/include/rendez.h b/kern/include/rendez.h
index e1d5720..9885bb5 100644
--- a/kern/include/rendez.h
+++ b/kern/include/rendez.h
@@ -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 @@
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);
diff --git a/kern/src/rendez.c b/kern/src/rendez.c
index f046556..cb3e81a 100644
--- a/kern/src/rendez.c
+++ b/kern/src/rendez.c
@@ -80,23 +80,24 @@
}
/* 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 @@
* 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 @@
/* 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