diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
commit | 2aa4a82499d4becd2284cdb482213d541b8804dd (patch) | |
tree | b80bf8bf13c3766139fbacc530efd0dd9d54394c /third_party/rust/tokio-executor/src/park.rs | |
parent | Initial commit. (diff) | |
download | firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.tar.xz firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.zip |
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/tokio-executor/src/park.rs')
-rw-r--r-- | third_party/rust/tokio-executor/src/park.rs | 226 |
1 files changed, 226 insertions, 0 deletions
diff --git a/third_party/rust/tokio-executor/src/park.rs b/third_party/rust/tokio-executor/src/park.rs new file mode 100644 index 0000000000..8626f089a1 --- /dev/null +++ b/third_party/rust/tokio-executor/src/park.rs @@ -0,0 +1,226 @@ +//! Abstraction over blocking and unblocking the current thread. +//! +//! Provides an abstraction over blocking the current thread. This is similar to +//! the park / unpark constructs provided by [`std`] but made generic. This +//! allows embedding custom functionality to perform when the thread is blocked. +//! +//! A blocked [`Park`][p] instance is unblocked by calling [`unpark`] on its +//! [`Unpark`][up] handle. +//! +//! The [`ParkThread`] struct implements [`Park`][p] using +//! [`thread::park`][`std`] to put the thread to sleep. The Tokio reactor also +//! implements park, but uses [`mio::Poll`][mio] to block the thread instead. +//! +//! The [`Park`][p] trait is composable. A timer implementation might decorate a +//! [`Park`][p] implementation by checking if any timeouts have elapsed after +//! the inner [`Park`][p] implementation unblocks. +//! +//! # Model +//! +//! Conceptually, each [`Park`][p] instance has an associated token, which is +//! initially not present: +//! +//! * The [`park`] method blocks the current thread unless or until the token +//! is available, at which point it atomically consumes the token. +//! * The [`unpark`] method atomically makes the token available if it wasn't +//! already. +//! +//! Some things to note: +//! +//! * If [`unpark`] is called before [`park`], the next call to [`park`] will +//! **not** block the thread. +//! * **Spurious** wakeups are permitted, i.e., the [`park`] method may unblock +//! even if [`unpark`] was not called. +//! * [`park_timeout`] does the same as [`park`] but allows specifying a maximum +//! time to block the thread for. +//! +//! [`std`]: https://doc.rust-lang.org/std/thread/fn.park.html +//! [`thread::park`]: https://doc.rust-lang.org/std/thread/fn.park.html +//! [`ParkThread`]: struct.ParkThread.html +//! [p]: trait.Park.html +//! [`park`]: trait.Park.html#tymethod.park +//! [`park_timeout`]: trait.Park.html#tymethod.park_timeout +//! [`unpark`]: trait.Unpark.html#tymethod.unpark +//! [up]: trait.Unpark.html +//! [mio]: https://docs.rs/mio/0.6/mio/struct.Poll.html + +use std::marker::PhantomData; +use std::rc::Rc; +use std::sync::Arc; +use std::time::Duration; + +use crossbeam_utils::sync::{Parker, Unparker}; + +/// Block the current thread. +/// +/// See [module documentation][mod] for more details. +/// +/// [mod]: ../index.html +pub trait Park { + /// Unpark handle type for the `Park` implementation. + type Unpark: Unpark; + + /// Error returned by `park` + type Error; + + /// Get a new `Unpark` handle associated with this `Park` instance. + fn unpark(&self) -> Self::Unpark; + + /// Block the current thread unless or until the token is available. + /// + /// A call to `park` does not guarantee that the thread will remain blocked + /// forever, and callers should be prepared for this possibility. This + /// function may wakeup spuriously for any reason. + /// + /// See [module documentation][mod] for more details. + /// + /// # Panics + /// + /// This function **should** not panic, but ultimately, panics are left as + /// an implementation detail. Refer to the documentation for the specific + /// `Park` implementation + /// + /// [mod]: ../index.html + fn park(&mut self) -> Result<(), Self::Error>; + + /// Park the current thread for at most `duration`. + /// + /// This function is the same as `park` but allows specifying a maximum time + /// to block the thread for. + /// + /// Same as `park`, there is no guarantee that the thread will remain + /// blocked for any amount of time. Spurious wakeups are permitted for any + /// reason. + /// + /// See [module documentation][mod] for more details. + /// + /// # Panics + /// + /// This function **should** not panic, but ultimately, panics are left as + /// an implementation detail. Refer to the documentation for the specific + /// `Park` implementation + /// + /// [mod]: ../index.html + fn park_timeout(&mut self, duration: Duration) -> Result<(), Self::Error>; +} + +/// Unblock a thread blocked by the associated [`Park`] instance. +/// +/// See [module documentation][mod] for more details. +/// +/// [mod]: ../index.html +/// [`Park`]: trait.Park.html +pub trait Unpark: Sync + Send + 'static { + /// Unblock a thread that is blocked by the associated `Park` handle. + /// + /// Calling `unpark` atomically makes available the unpark token, if it is + /// not already available. + /// + /// See [module documentation][mod] for more details. + /// + /// # Panics + /// + /// This function **should** not panic, but ultimately, panics are left as + /// an implementation detail. Refer to the documentation for the specific + /// `Unpark` implementation + /// + /// [mod]: ../index.html + fn unpark(&self); +} + +impl Unpark for Box<dyn Unpark> { + fn unpark(&self) { + (**self).unpark() + } +} + +impl Unpark for Arc<dyn Unpark> { + fn unpark(&self) { + (**self).unpark() + } +} + +/// Blocks the current thread using a condition variable. +/// +/// Implements the [`Park`] functionality by using a condition variable. An +/// atomic variable is also used to avoid using the condition variable if +/// possible. +/// +/// The condition variable is cached in a thread-local variable and is shared +/// across all `ParkThread` instances created on the same thread. This also +/// means that an instance of `ParkThread` might be unblocked by a handle +/// associated with a different `ParkThread` instance. +#[derive(Debug)] +pub struct ParkThread { + _anchor: PhantomData<Rc<()>>, +} + +/// Error returned by [`ParkThread`] +/// +/// This currently is never returned, but might at some point in the future. +/// +/// [`ParkThread`]: struct.ParkThread.html +#[derive(Debug)] +pub struct ParkError { + _p: (), +} + +/// Unblocks a thread that was blocked by `ParkThread`. +#[derive(Clone, Debug)] +pub struct UnparkThread { + inner: Unparker, +} + +thread_local! { + static CURRENT_PARKER: Parker = Parker::new(); +} + +// ===== impl ParkThread ===== + +impl ParkThread { + /// Create a new `ParkThread` handle for the current thread. + /// + /// This type cannot be moved to other threads, so it should be created on + /// the thread that the caller intends to park. + pub fn new() -> ParkThread { + ParkThread { + _anchor: PhantomData, + } + } + + /// Get a reference to the `ParkThread` handle for this thread. + fn with_current<F, R>(&self, f: F) -> R + where + F: FnOnce(&Parker) -> R, + { + CURRENT_PARKER.with(|inner| f(inner)) + } +} + +impl Park for ParkThread { + type Unpark = UnparkThread; + type Error = ParkError; + + fn unpark(&self) -> Self::Unpark { + let inner = self.with_current(|inner| inner.unparker().clone()); + UnparkThread { inner } + } + + fn park(&mut self) -> Result<(), Self::Error> { + self.with_current(|inner| inner.park()); + Ok(()) + } + + fn park_timeout(&mut self, duration: Duration) -> Result<(), Self::Error> { + self.with_current(|inner| inner.park_timeout(duration)); + Ok(()) + } +} + +// ===== impl UnparkThread ===== + +impl Unpark for UnparkThread { + fn unpark(&self) { + self.inner.unpark(); + } +} |