Skip to content

Commit

Permalink
Revert "Remove UnparkReason to preserve compatibility." (#1012)
Browse files Browse the repository at this point in the history
This reverts commit 4c0a106.
  • Loading branch information
taiki-e authored Sep 12, 2023
1 parent 4bb27db commit e48ece5
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 15 deletions.
2 changes: 1 addition & 1 deletion crossbeam-utils/src/sync/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ mod parker;
mod sharded_lock;
mod wait_group;

pub use self::parker::{Parker, Unparker};
pub use self::parker::{Parker, UnparkReason, Unparker};
#[cfg(not(crossbeam_loom))]
pub use self::sharded_lock::{ShardedLock, ShardedLockReadGuard, ShardedLockWriteGuard};
pub use self::wait_group::WaitGroup;
36 changes: 26 additions & 10 deletions crossbeam-utils/src/sync/parker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,10 +121,13 @@ impl Parker {
/// // Waits for the token to become available, but will not wait longer than 500 ms.
/// p.park_timeout(Duration::from_millis(500));
/// ```
pub fn park_timeout(&self, timeout: Duration) {
pub fn park_timeout(&self, timeout: Duration) -> UnparkReason {
match Instant::now().checked_add(timeout) {
Some(deadline) => self.park_deadline(deadline),
None => self.park(),
None => {
self.park();
UnparkReason::Unparked
}
}
}

Expand All @@ -142,7 +145,7 @@ impl Parker {
/// // Waits for the token to become available, but will not wait longer than 500 ms.
/// p.park_deadline(deadline);
/// ```
pub fn park_deadline(&self, deadline: Instant) {
pub fn park_deadline(&self, deadline: Instant) -> UnparkReason {
self.unparker.inner.park(Some(deadline))
}

Expand Down Expand Up @@ -308,6 +311,18 @@ impl Clone for Unparker {
}
}

/// An enum that reports whether a `Parker::park_timeout` or
/// `Parker::park_deadline` returned because another thread called `unpark` or
/// because of a timeout.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum UnparkReason {
/// The park method returned due to a call to `unpark`.
Unparked,

/// The park method returned due to a timeout.
Timeout,
}

const EMPTY: usize = 0;
const PARKED: usize = 1;
const NOTIFIED: usize = 2;
Expand All @@ -319,20 +334,20 @@ struct Inner {
}

impl Inner {
fn park(&self, deadline: Option<Instant>) {
fn park(&self, deadline: Option<Instant>) -> UnparkReason {
// If we were previously notified then we consume this notification and return quickly.
if self
.state
.compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst)
.is_ok()
{
return;
return UnparkReason::Unparked;
}

// If the timeout is zero, then there is no need to actually block.
if let Some(deadline) = deadline {
if deadline <= Instant::now() {
return;
return UnparkReason::Timeout;
}
}

Expand All @@ -350,7 +365,7 @@ impl Inner {
// do that we must read from the write it made to `state`.
let old = self.state.swap(EMPTY, SeqCst);
assert_eq!(old, NOTIFIED, "park state changed unexpectedly");
return;
return UnparkReason::Unparked;
}
Err(n) => panic!("inconsistent park_timeout state: {}", n),
}
Expand All @@ -368,8 +383,9 @@ impl Inner {
self.cvar.wait_timeout(m, deadline - now).unwrap().0
} else {
// We've timed out; swap out the state back to empty on our way out
match self.state.swap(EMPTY, SeqCst) {
NOTIFIED | PARKED => return,
return match self.state.swap(EMPTY, SeqCst) {
NOTIFIED => UnparkReason::Unparked, // got a notification
PARKED => UnparkReason::Timeout, // no notification
n => panic!("inconsistent park_timeout state: {}", n),
};
}
Expand All @@ -382,7 +398,7 @@ impl Inner {
.is_ok()
{
// got a notification
return;
return UnparkReason::Unparked;
}

// Spurious wakeup, go back to sleep. Alternatively, if we timed out, it will be caught
Expand Down
17 changes: 13 additions & 4 deletions crossbeam-utils/tests/parker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,29 @@ use std::thread::sleep;
use std::time::Duration;
use std::u32;

use crossbeam_utils::sync::Parker;
use crossbeam_utils::sync::{Parker, UnparkReason};
use crossbeam_utils::thread;

#[test]
fn park_timeout_unpark_before() {
let p = Parker::new();
for _ in 0..10 {
p.unparker().unpark();
p.park_timeout(Duration::from_millis(u32::MAX as u64));
assert_eq!(
p.park_timeout(Duration::from_millis(u32::MAX as u64)),
UnparkReason::Unparked,
);
}
}

#[test]
fn park_timeout_unpark_not_called() {
let p = Parker::new();
for _ in 0..10 {
p.park_timeout(Duration::from_millis(10))
assert_eq!(
p.park_timeout(Duration::from_millis(10)),
UnparkReason::Timeout,
);
}
}

Expand All @@ -34,7 +40,10 @@ fn park_timeout_unpark_called_other_thread() {
u.unpark();
});

p.park_timeout(Duration::from_millis(u32::MAX as u64))
assert_eq!(
p.park_timeout(Duration::from_millis(u32::MAX as u64)),
UnparkReason::Unparked,
);
})
.unwrap();
}
Expand Down

0 comments on commit e48ece5

Please sign in to comment.