add local-waker crate

This commit is contained in:
Rob Ede 2021-03-29 09:46:24 +01:00
parent 26a5af70cb
commit 270d54eb47
No known key found for this signature in database
GPG Key ID: 97C636207D3EF933
4 changed files with 93 additions and 0 deletions

View File

@ -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" }

7
local-waker/CHANGES.md Normal file
View File

@ -0,0 +1,7 @@
# Changes
## Unreleased - 2021-xx-xx
## 0.1.0 - 2021-03-29
* Move `LocalWaker` to it's own crate.

13
local-waker/Cargo.toml Normal file
View File

@ -0,0 +1,13 @@
[package]
name = "local-waker"
version = "0.1.0"
description = "A synchronization primitive for thread-local task wakeup"
authors = ["Rob Ede <robjtede@icloud.com>"]
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]

71
local-waker/src/lib.rs Normal file
View File

@ -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<Option<Waker>>,
// 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<Waker> {
self.waker.take()
}
}
impl fmt::Debug for LocalWaker {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "LocalWaker")
}
}