Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stabilize basic timeout functionality #23949

Merged
merged 1 commit into from
Apr 2, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 31 additions & 19 deletions src/libstd/sync/condvar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,33 +140,43 @@ impl Condvar {
/// Wait on this condition variable for a notification, timing out after a
/// specified duration.
///
/// The semantics of this function are equivalent to `wait()` except that
/// the thread will be blocked for roughly no longer than `dur`. This method
/// should not be used for precise timing due to anomalies such as
/// preemption or platform differences that may not cause the maximum amount
/// of time waited to be precisely `dur`.
/// The semantics of this function are equivalent to `wait()`
/// except that the thread will be blocked for roughly no longer
/// than `ms` milliseconds. This method should not be used for
/// precise timing due to anomalies such as preemption or platform
/// differences that may not cause the maximum amount of time
/// waited to be precisely `ms`.
///
/// If the wait timed out, then `false` will be returned. Otherwise if a
/// notification was received then `true` will be returned.
/// The returned boolean is `false` only if the timeout is known
/// to have elapsed.
///
/// Like `wait`, the lock specified will be re-acquired when this function
/// returns, regardless of whether the timeout elapsed or not.
#[unstable(feature = "std_misc")]
pub fn wait_timeout<'a, T>(&self, guard: MutexGuard<'a, T>, dur: Duration)
-> LockResult<(MutexGuard<'a, T>, bool)> {
#[stable(feature = "rust1", since = "1.0.0")]
pub fn wait_timeout_ms<'a, T>(&self, guard: MutexGuard<'a, T>, ms: u32)
-> LockResult<(MutexGuard<'a, T>, bool)> {
unsafe {
let me: &'static Condvar = &*(self as *const _);
me.inner.wait_timeout(guard, dur)
me.inner.wait_timeout_ms(guard, ms)
}
}

/// Deprecated: use `wait_timeout_ms` instead.
#[unstable(feature = "std_misc")]
#[deprecated(since = "1.0.0", reason = "use wait_timeout_ms instead")]
pub fn wait_timeout<'a, T>(&self, guard: MutexGuard<'a, T>, dur: Duration)
-> LockResult<(MutexGuard<'a, T>, bool)> {
self.wait_timeout_ms(guard, dur.num_milliseconds() as u32)
}

/// Wait on this condition variable for a notification, timing out after a
/// specified duration.
///
/// The semantics of this function are equivalent to `wait_timeout` except
/// that the implementation will repeatedly wait while the duration has not
/// passed and the provided function returns `false`.
#[unstable(feature = "std_misc")]
#[unstable(feature = "wait_timeout_with",
reason = "unsure if this API is broadly needed or what form it should take")]
pub fn wait_timeout_with<'a, T, F>(&self,
guard: MutexGuard<'a, T>,
dur: Duration,
Expand Down Expand Up @@ -235,12 +245,12 @@ impl StaticCondvar {
/// See `Condvar::wait_timeout`.
#[unstable(feature = "std_misc",
reason = "may be merged with Condvar in the future")]
pub fn wait_timeout<'a, T>(&'static self, guard: MutexGuard<'a, T>, dur: Duration)
-> LockResult<(MutexGuard<'a, T>, bool)> {
pub fn wait_timeout_ms<'a, T>(&'static self, guard: MutexGuard<'a, T>, ms: u32)
-> LockResult<(MutexGuard<'a, T>, bool)> {
let (poisoned, success) = unsafe {
let lock = mutex::guard_lock(&guard);
self.verify(lock);
let success = self.inner.wait_timeout(lock, dur);
let success = self.inner.wait_timeout(lock, Duration::milliseconds(ms as i64));
(mutex::guard_poison(&guard).get(), success)
};
if poisoned {
Expand Down Expand Up @@ -275,7 +285,8 @@ impl StaticCondvar {
let now = SteadyTime::now();
let consumed = &now - &start;
let guard = guard_result.unwrap_or_else(|e| e.into_inner());
let (new_guard_result, no_timeout) = match self.wait_timeout(guard, dur - consumed) {
let res = self.wait_timeout_ms(guard, (dur - consumed).num_milliseconds() as u32);
let (new_guard_result, no_timeout) = match res {
Ok((new_guard, no_timeout)) => (Ok(new_guard), no_timeout),
Err(err) => {
let (new_guard, no_timeout) = err.into_inner();
Expand Down Expand Up @@ -350,6 +361,7 @@ mod tests {
use sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
use thread;
use time::Duration;
use u32;

#[test]
fn smoke() {
Expand Down Expand Up @@ -418,19 +430,19 @@ mod tests {
}

#[test]
fn wait_timeout() {
fn wait_timeout_ms() {
static C: StaticCondvar = CONDVAR_INIT;
static M: StaticMutex = MUTEX_INIT;

let g = M.lock().unwrap();
let (g, _no_timeout) = C.wait_timeout(g, Duration::nanoseconds(1000)).unwrap();
let (g, _no_timeout) = C.wait_timeout_ms(g, 1).unwrap();
// spurious wakeups mean this isn't necessarily true
// assert!(!no_timeout);
let _t = thread::spawn(move || {
let _g = M.lock().unwrap();
C.notify_one();
});
let (g, no_timeout) = C.wait_timeout(g, Duration::days(1)).unwrap();
let (g, no_timeout) = C.wait_timeout_ms(g, u32::MAX).unwrap();
assert!(no_timeout);
drop(g);
unsafe { C.destroy(); M.destroy(); }
Expand Down
32 changes: 23 additions & 9 deletions src/libstd/thread/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -465,9 +465,16 @@ pub fn catch_panic<F, R>(f: F) -> Result<R>
/// specifics or platform-dependent functionality. Note that on unix platforms
/// this function will not return early due to a signal being received or a
/// spurious wakeup.
#[stable(feature = "rust1", since = "1.0.0")]
pub fn sleep_ms(ms: u32) {
imp::sleep(Duration::milliseconds(ms as i64))
}

/// Deprecated: use `sleep_ms` instead.
#[unstable(feature = "thread_sleep",
reason = "recently added, needs an RFC, and `Duration` itself is \
unstable")]
#[deprecated(since = "1.0.0", reason = "use sleep_ms instead")]
pub fn sleep(dur: Duration) {
imp::sleep(dur)
}
Expand Down Expand Up @@ -501,17 +508,24 @@ pub fn park() {
/// amount of time waited to be precisely *duration* long.
///
/// See the module doc for more detail.
#[unstable(feature = "std_misc", reason = "recently introduced, depends on Duration")]
pub fn park_timeout(duration: Duration) {
#[stable(feature = "rust1", since = "1.0.0")]
pub fn park_timeout_ms(ms: u32) {
let thread = current();
let mut guard = thread.inner.lock.lock().unwrap();
if !*guard {
let (g, _) = thread.inner.cvar.wait_timeout(guard, duration).unwrap();
let (g, _) = thread.inner.cvar.wait_timeout_ms(guard, ms).unwrap();
guard = g;
}
*guard = false;
}

/// Deprecated: use `park_timeout_ms`
#[unstable(feature = "std_misc", reason = "recently introduced, depends on Duration")]
#[deprecated(since = "1.0.0", reason = "use park_timeout_ms instead")]
pub fn park_timeout(duration: Duration) {
park_timeout_ms(duration.num_milliseconds() as u32)
}

////////////////////////////////////////////////////////////////////////////////
// Thread
////////////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -716,6 +730,7 @@ mod test {
use thread;
use thunk::Thunk;
use time::Duration;
use u32;

// !!! These tests are dangerous. If something is buggy, they will hang, !!!
// !!! instead of exiting cleanly. This might wedge the buildbots. !!!
Expand Down Expand Up @@ -936,14 +951,14 @@ mod test {
fn test_park_timeout_unpark_before() {
for _ in 0..10 {
thread::current().unpark();
thread::park_timeout(Duration::seconds(10_000_000));
thread::park_timeout_ms(u32::MAX);
}
}

#[test]
fn test_park_timeout_unpark_not_called() {
for _ in 0..10 {
thread::park_timeout(Duration::milliseconds(10));
thread::park_timeout_ms(10);
}
}

Expand All @@ -959,14 +974,13 @@ mod test {
th.unpark();
});

thread::park_timeout(Duration::seconds(10_000_000));
thread::park_timeout_ms(u32::MAX);
}
}

#[test]
fn sleep_smoke() {
thread::sleep(Duration::milliseconds(2));
thread::sleep(Duration::milliseconds(-2));
fn sleep_ms_smoke() {
thread::sleep_ms(2);
}

// NOTE: the corresponding test for stderr is in run-pass/task-stderr, due
Expand Down