Skip to content

Commit 983d2b3

Browse files
committed
Auto merge of #27826 - sfackler:wait-timeout-enum, r=alexcrichton
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] r? @alexcrichton
2 parents a03ec1a + 12216b7 commit 983d2b3

File tree

2 files changed

+42
-21
lines changed

2 files changed

+42
-21
lines changed

src/libstd/sync/condvar.rs

Lines changed: 41 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,20 @@ 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, Copy, Clone)]
24+
#[unstable(feature = "wait_timeout", reason = "newly added", issue = "27772")]
25+
pub struct WaitTimeoutResult(bool);
26+
27+
impl WaitTimeoutResult {
28+
/// Returns whether the wait was known to have timed out.
29+
#[unstable(feature = "wait_timeout", reason = "newly added", issue = "27772")]
30+
pub fn timed_out(&self) -> bool {
31+
self.0
32+
}
33+
}
34+
2135
/// A Condition Variable
2236
///
2337
/// Condition variables represent the ability to block a thread such that it
@@ -170,16 +184,16 @@ impl Condvar {
170184
/// preemption or platform differences that may not cause the maximum
171185
/// amount of time waited to be precisely `dur`.
172186
///
173-
/// The returned boolean is `false` only if the timeout is known
174-
/// to have elapsed.
187+
/// The returned `WaitTimeoutResult` value indicates if the timeout is
188+
/// known to have elapsed.
175189
///
176190
/// Like `wait`, the lock specified will be re-acquired when this function
177191
/// returns, regardless of whether the timeout elapsed or not.
178192
#[unstable(feature = "wait_timeout", reason = "waiting for Duration",
179193
issue = "27772")]
180194
pub fn wait_timeout<'a, T>(&self, guard: MutexGuard<'a, T>,
181195
dur: Duration)
182-
-> LockResult<(MutexGuard<'a, T>, bool)> {
196+
-> LockResult<(MutexGuard<'a, T>, WaitTimeoutResult)> {
183197
unsafe {
184198
let me: &'static Condvar = &*(self as *const _);
185199
me.inner.wait_timeout(guard, dur)
@@ -199,7 +213,7 @@ impl Condvar {
199213
guard: MutexGuard<'a, T>,
200214
dur: Duration,
201215
f: F)
202-
-> LockResult<(MutexGuard<'a, T>, bool)>
216+
-> LockResult<(MutexGuard<'a, T>, WaitTimeoutResult)>
203217
where F: FnMut(LockResult<&mut T>) -> bool {
204218
unsafe {
205219
let me: &'static Condvar = &*(self as *const _);
@@ -278,7 +292,13 @@ impl StaticCondvar {
278292
issue = "27717")]
279293
pub fn wait_timeout_ms<'a, T>(&'static self, guard: MutexGuard<'a, T>, ms: u32)
280294
-> LockResult<(MutexGuard<'a, T>, bool)> {
281-
self.wait_timeout(guard, Duration::from_millis(ms as u64))
295+
match self.wait_timeout(guard, Duration::from_millis(ms as u64)) {
296+
Ok((guard, timed_out)) => Ok((guard, !timed_out.timed_out())),
297+
Err(poison) => {
298+
let (guard, timed_out) = poison.into_inner();
299+
Err(PoisonError::new((guard, !timed_out.timed_out())))
300+
}
301+
}
282302
}
283303

284304
/// Waits on this condition variable for a notification, timing out after a
@@ -291,17 +311,17 @@ impl StaticCondvar {
291311
pub fn wait_timeout<'a, T>(&'static self,
292312
guard: MutexGuard<'a, T>,
293313
timeout: Duration)
294-
-> LockResult<(MutexGuard<'a, T>, bool)> {
295-
let (poisoned, success) = unsafe {
314+
-> LockResult<(MutexGuard<'a, T>, WaitTimeoutResult)> {
315+
let (poisoned, result) = unsafe {
296316
let lock = mutex::guard_lock(&guard);
297317
self.verify(lock);
298318
let success = self.inner.wait_timeout(lock, timeout);
299-
(mutex::guard_poison(&guard).get(), success)
319+
(mutex::guard_poison(&guard).get(), WaitTimeoutResult(!success))
300320
};
301321
if poisoned {
302-
Err(PoisonError::new((guard, success)))
322+
Err(PoisonError::new((guard, result)))
303323
} else {
304-
Ok((guard, success))
324+
Ok((guard, result))
305325
}
306326
}
307327

@@ -319,7 +339,7 @@ impl StaticCondvar {
319339
guard: MutexGuard<'a, T>,
320340
dur: Duration,
321341
mut f: F)
322-
-> LockResult<(MutexGuard<'a, T>, bool)>
342+
-> LockResult<(MutexGuard<'a, T>, WaitTimeoutResult)>
323343
where F: FnMut(LockResult<&mut T>) -> bool {
324344
// This could be made more efficient by pushing the implementation into
325345
// sys::condvar
@@ -332,28 +352,29 @@ impl StaticCondvar {
332352
let now = SteadyTime::now();
333353
let consumed = &now - &start;
334354
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)
355+
let (new_guard_result, timed_out) = if consumed > dur {
356+
(Ok(guard), WaitTimeoutResult(true))
337357
} else {
338358
match self.wait_timeout(guard, dur - consumed) {
339-
Ok((new_guard, no_timeout)) => (Ok(new_guard), no_timeout),
359+
Ok((new_guard, timed_out)) => (Ok(new_guard), timed_out),
340360
Err(err) => {
341361
let (new_guard, no_timeout) = err.into_inner();
342362
(Err(PoisonError::new(new_guard)), no_timeout)
343363
}
344364
}
345365
};
346366
guard_result = new_guard_result;
347-
if !no_timeout {
367+
if timed_out.timed_out() {
348368
let result = f(guard_result
349369
.as_mut()
350370
.map(|g| &mut **g)
351371
.map_err(|e| PoisonError::new(&mut **e.get_mut())));
372+
let result = WaitTimeoutResult(!result);
352373
return poison::map_result(guard_result, |g| (g, result));
353374
}
354375
}
355376

356-
poison::map_result(guard_result, |g| (g, true))
377+
poison::map_result(guard_result, |g| (g, WaitTimeoutResult(false)))
357378
}
358379

359380
/// Wakes up one blocked thread on this condvar.
@@ -508,10 +529,10 @@ mod tests {
508529
static S: AtomicUsize = AtomicUsize::new(0);
509530

510531
let g = M.lock().unwrap();
511-
let (g, success) = C.wait_timeout_with(g, Duration::new(0, 1000), |_| {
532+
let (g, timed_out) = C.wait_timeout_with(g, Duration::new(0, 1000), |_| {
512533
false
513534
}).unwrap();
514-
assert!(!success);
535+
assert!(timed_out.timed_out());
515536

516537
let (tx, rx) = channel();
517538
let _t = thread::spawn(move || {
@@ -535,7 +556,7 @@ mod tests {
535556

536557
let mut state = 0;
537558
let day = 24 * 60 * 60;
538-
let (_g, success) = C.wait_timeout_with(g, Duration::new(day, 0), |_| {
559+
let (_g, timed_out) = C.wait_timeout_with(g, Duration::new(day, 0), |_| {
539560
assert_eq!(state, S.load(Ordering::SeqCst));
540561
tx.send(()).unwrap();
541562
state += 1;
@@ -544,7 +565,7 @@ mod tests {
544565
_ => true,
545566
}
546567
}).unwrap();
547-
assert!(success);
568+
assert!(!timed_out.timed_out());
548569
}
549570

550571
#[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, WaitTimeoutResult, 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)