Skip to content

Commit 42a386f

Browse files
committed
Make Condvar::wait_timeout return an enum instead of a bool
Returning a primitive bool results in a somewhat confusing API - does `true` indicate success - i.e. no timeout, or that a timeout has occurred? An explicitly named enum makes it clearer. [breaking-change]
1 parent aca2057 commit 42a386f

File tree

2 files changed

+45
-19
lines changed

2 files changed

+45
-19
lines changed

src/libstd/sync/condvar.rs

Lines changed: 44 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,17 @@ use sys_common::poison::{self, LockResult};
1818
use sys::time::SteadyTime;
1919
use time::Duration;
2020

21+
/// A type indicating whether a timed wait on a condition variable returned
22+
/// due to a time out or not.
23+
#[derive(Debug, PartialEq, Eq)]
24+
#[unstable(feature = "wait_timeout", reason = "newly added")]
25+
pub enum TimedOut {
26+
/// The wait timed out.
27+
Yes,
28+
/// The wait did not time out.
29+
No
30+
}
31+
2132
/// A Condition Variable
2233
///
2334
/// Condition variables represent the ability to block a thread such that it
@@ -170,16 +181,16 @@ impl Condvar {
170181
/// preemption or platform differences that may not cause the maximum
171182
/// amount of time waited to be precisely `dur`.
172183
///
173-
/// The returned boolean is `false` only if the timeout is known
174-
/// to have elapsed.
184+
/// The returned `TimedOut` value indicates if the timeout is known to have
185+
/// elapsed.
175186
///
176187
/// Like `wait`, the lock specified will be re-acquired when this function
177188
/// returns, regardless of whether the timeout elapsed or not.
178189
#[unstable(feature = "wait_timeout", reason = "waiting for Duration",
179190
issue = "27772")]
180191
pub fn wait_timeout<'a, T>(&self, guard: MutexGuard<'a, T>,
181192
dur: Duration)
182-
-> LockResult<(MutexGuard<'a, T>, bool)> {
193+
-> LockResult<(MutexGuard<'a, T>, TimedOut)> {
183194
unsafe {
184195
let me: &'static Condvar = &*(self as *const _);
185196
me.inner.wait_timeout(guard, dur)
@@ -199,7 +210,7 @@ impl Condvar {
199210
guard: MutexGuard<'a, T>,
200211
dur: Duration,
201212
f: F)
202-
-> LockResult<(MutexGuard<'a, T>, bool)>
213+
-> LockResult<(MutexGuard<'a, T>, TimedOut)>
203214
where F: FnMut(LockResult<&mut T>) -> bool {
204215
unsafe {
205216
let me: &'static Condvar = &*(self as *const _);
@@ -278,7 +289,13 @@ impl StaticCondvar {
278289
issue = "27717")]
279290
pub fn wait_timeout_ms<'a, T>(&'static self, guard: MutexGuard<'a, T>, ms: u32)
280291
-> LockResult<(MutexGuard<'a, T>, bool)> {
281-
self.wait_timeout(guard, Duration::from_millis(ms as u64))
292+
match self.wait_timeout(guard, Duration::from_millis(ms as u64)) {
293+
Ok((guard, timed_out)) => Ok((guard, timed_out == TimedOut::No)),
294+
Err(poison) => {
295+
let (guard, timed_out) = poison.into_inner();
296+
Err(PoisonError::new((guard, timed_out == TimedOut::No)))
297+
}
298+
}
282299
}
283300

284301
/// Waits on this condition variable for a notification, timing out after a
@@ -291,11 +308,15 @@ impl StaticCondvar {
291308
pub fn wait_timeout<'a, T>(&'static self,
292309
guard: MutexGuard<'a, T>,
293310
timeout: Duration)
294-
-> LockResult<(MutexGuard<'a, T>, bool)> {
311+
-> LockResult<(MutexGuard<'a, T>, TimedOut)> {
295312
let (poisoned, success) = unsafe {
296313
let lock = mutex::guard_lock(&guard);
297314
self.verify(lock);
298-
let success = self.inner.wait_timeout(lock, timeout);
315+
let success = if self.inner.wait_timeout(lock, timeout) {
316+
TimedOut::No
317+
} else {
318+
TimedOut::Yes
319+
};
299320
(mutex::guard_poison(&guard).get(), success)
300321
};
301322
if poisoned {
@@ -319,7 +340,7 @@ impl StaticCondvar {
319340
guard: MutexGuard<'a, T>,
320341
dur: Duration,
321342
mut f: F)
322-
-> LockResult<(MutexGuard<'a, T>, bool)>
343+
-> LockResult<(MutexGuard<'a, T>, TimedOut)>
323344
where F: FnMut(LockResult<&mut T>) -> bool {
324345
// This could be made more efficient by pushing the implementation into
325346
// sys::condvar
@@ -332,28 +353,33 @@ impl StaticCondvar {
332353
let now = SteadyTime::now();
333354
let consumed = &now - &start;
334355
let guard = guard_result.unwrap_or_else(|e| e.into_inner());
335-
let (new_guard_result, no_timeout) = if consumed > dur {
336-
(Ok(guard), false)
356+
let (new_guard_result, timed_out) = if consumed > dur {
357+
(Ok(guard), TimedOut::Yes)
337358
} else {
338359
match self.wait_timeout(guard, dur - consumed) {
339-
Ok((new_guard, no_timeout)) => (Ok(new_guard), no_timeout),
360+
Ok((new_guard, timed_out)) => (Ok(new_guard), timed_out),
340361
Err(err) => {
341362
let (new_guard, no_timeout) = err.into_inner();
342363
(Err(PoisonError::new(new_guard)), no_timeout)
343364
}
344365
}
345366
};
346367
guard_result = new_guard_result;
347-
if !no_timeout {
368+
if timed_out == TimedOut::Yes {
348369
let result = f(guard_result
349370
.as_mut()
350371
.map(|g| &mut **g)
351372
.map_err(|e| PoisonError::new(&mut **e.get_mut())));
373+
let result = if result {
374+
TimedOut::No
375+
} else {
376+
TimedOut::Yes
377+
};
352378
return poison::map_result(guard_result, |g| (g, result));
353379
}
354380
}
355381

356-
poison::map_result(guard_result, |g| (g, true))
382+
poison::map_result(guard_result, |g| (g, TimedOut::No))
357383
}
358384

359385
/// Wakes up one blocked thread on this condvar.
@@ -410,7 +436,7 @@ mod tests {
410436

411437
use super::StaticCondvar;
412438
use sync::mpsc::channel;
413-
use sync::{StaticMutex, Condvar, Mutex, Arc};
439+
use sync::{StaticMutex, Condvar, Mutex, Arc, TimedOut};
414440
use sync::atomic::{AtomicUsize, Ordering};
415441
use thread;
416442
use time::Duration;
@@ -508,10 +534,10 @@ mod tests {
508534
static S: AtomicUsize = AtomicUsize::new(0);
509535

510536
let g = M.lock().unwrap();
511-
let (g, success) = C.wait_timeout_with(g, Duration::new(0, 1000), |_| {
537+
let (g, timed_out) = C.wait_timeout_with(g, Duration::new(0, 1000), |_| {
512538
false
513539
}).unwrap();
514-
assert!(!success);
540+
assert_eq!(timed_out, TimedOut::Yes);
515541

516542
let (tx, rx) = channel();
517543
let _t = thread::spawn(move || {
@@ -535,7 +561,7 @@ mod tests {
535561

536562
let mut state = 0;
537563
let day = 24 * 60 * 60;
538-
let (_g, success) = C.wait_timeout_with(g, Duration::new(day, 0), |_| {
564+
let (_g, timed_out) = C.wait_timeout_with(g, Duration::new(day, 0), |_| {
539565
assert_eq!(state, S.load(Ordering::SeqCst));
540566
tx.send(()).unwrap();
541567
state += 1;
@@ -544,7 +570,7 @@ mod tests {
544570
_ => true,
545571
}
546572
}).unwrap();
547-
assert!(success);
573+
assert_eq!(timed_out, TimedOut::No);
548574
}
549575

550576
#[test]

src/libstd/sync/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ pub use alloc::arc::{Arc, Weak};
2121
pub use core::atomic;
2222

2323
pub use self::barrier::{Barrier, BarrierWaitResult};
24-
pub use self::condvar::{Condvar, StaticCondvar, CONDVAR_INIT};
24+
pub use self::condvar::{Condvar, StaticCondvar, TimedOut, CONDVAR_INIT};
2525
pub use self::mutex::MUTEX_INIT;
2626
pub use self::mutex::{Mutex, MutexGuard, StaticMutex};
2727
pub use self::once::{Once, ONCE_INIT};

0 commit comments

Comments
 (0)