From 270d54eb47a6dcd1fbe7fc01e40263c1cee66441 Mon Sep 17 00:00:00 2001 From: Rob Ede Date: Mon, 29 Mar 2021 09:46:24 +0100 Subject: [PATCH] add local-waker crate --- Cargo.toml | 2 ++ local-waker/CHANGES.md | 7 +++++ local-waker/Cargo.toml | 13 ++++++++ local-waker/src/lib.rs | 71 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 93 insertions(+) create mode 100644 local-waker/CHANGES.md create mode 100644 local-waker/Cargo.toml create mode 100644 local-waker/src/lib.rs diff --git a/Cargo.toml b/Cargo.toml index 78e54d35..738f09ba 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,6 +10,7 @@ members = [ "actix-tracing", "actix-utils", "bytestring", + "local-waker", ] [patch.crates-io] @@ -23,3 +24,4 @@ actix-tls = { path = "actix-tls" } actix-tracing = { path = "actix-tracing" } actix-utils = { path = "actix-utils" } bytestring = { path = "bytestring" } +local-waker = { path = "local-waker" } diff --git a/local-waker/CHANGES.md b/local-waker/CHANGES.md new file mode 100644 index 00000000..2b8d3e30 --- /dev/null +++ b/local-waker/CHANGES.md @@ -0,0 +1,7 @@ +# Changes + +## Unreleased - 2021-xx-xx + + +## 0.1.0 - 2021-03-29 +* Move `LocalWaker` to it's own crate. diff --git a/local-waker/Cargo.toml b/local-waker/Cargo.toml new file mode 100644 index 00000000..166454bf --- /dev/null +++ b/local-waker/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "local-waker" +version = "0.1.0" +description = "A synchronization primitive for thread-local task wakeup" +authors = ["Rob Ede "] +keywords = ["waker", "local", "futures", "no-std"] +repository = "https://github.com/actix/actix-net.git" +documentation = "https://docs.rs/local-waker" +categories = ["asynchronous", "no-std"] +license = "MIT OR Apache-2.0" +edition = "2018" + +[dependencies] diff --git a/local-waker/src/lib.rs b/local-waker/src/lib.rs new file mode 100644 index 00000000..c76badee --- /dev/null +++ b/local-waker/src/lib.rs @@ -0,0 +1,71 @@ +//! A synchronization primitive for thread-local task wakeup. +//! +//! See docs for [`LocalWaker`]. + +#![no_std] + +use core::{cell::Cell, fmt, marker::PhantomData, task::Waker}; + +/// A synchronization primitive for task wakeup. +/// +/// Sometimes the task interested in a given event will change over time. A `LocalWaker` can +/// coordinate concurrent notifications with the consumer, potentially "updating" the underlying +/// task to wake up. This is useful in scenarios where a computation completes in another task and +/// wants to notify the consumer, but the consumer is in the process of being migrated to a new +/// logical task. +/// +/// Consumers should call [`register`] before checking the result of a computation and producers +/// should call [`wake`] after producing the computation (this differs from the usual `thread::park` +/// pattern). It is also permitted for [`wake`] to be called _before_ [`register`]. This results in +/// a no-op. +/// +/// A single `LocalWaker` may be reused for any number of calls to [`register`] or [`wake`]. +/// +/// [`register`]: LocalWaker::register +/// [`wake`]: LocalWaker::wake +#[derive(Default)] +pub struct LocalWaker { + pub(crate) waker: Cell>, + // mark LocalWaker as a !Send type. + _phantom: PhantomData<*const ()>, +} + +impl LocalWaker { + /// Creates a new, empty `LocalWaker`. + pub fn new() -> Self { + LocalWaker::default() + } + + /// Registers the waker to be notified on calls to `wake`. + /// + /// Returns `true` if waker was registered before. + #[inline] + pub fn register(&self, waker: &Waker) -> bool { + let last_waker = self.waker.replace(Some(waker.clone())); + last_waker.is_some() + } + + /// Calls `wake` on the last `Waker` passed to `register`. + /// + /// If `register` has not been called yet, then this does nothing. + #[inline] + pub fn wake(&self) { + if let Some(waker) = self.take() { + waker.wake(); + } + } + + /// Returns the last `Waker` passed to `register`, so that the user can wake it. + /// + /// If a waker has not been registered, this returns `None`. + #[inline] + pub fn take(&self) -> Option { + self.waker.take() + } +} + +impl fmt::Debug for LocalWaker { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "LocalWaker") + } +}