Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Difference From wakerizer-0.1.0 To wakerizer-0.2.0
|
2025-04-05
| ||
| 14:41 | Release maintenance. Leaf check-in: ef7a5da54f user: jan tags: trunk, wakerizer-0.2.0 | |
| 14:28 | Merge. check-in: e57772d3a5 user: jan tags: trunk | |
| 01:30 | Remove wake_one(). Replace IndexMap with rustc-hash::FxHashMap. Closed-Leaf check-in: 390d406790 user: jan tags: 0.2.0-wip | |
|
2025-04-01
| ||
| 01:15 | Move from old repo. check-in: 579045bbba user: jan tags: trunk, wakerizer-0.1.0 | |
| 01:02 | initial empty check-in check-in: a8735ea926 user: jan tags: trunk | |
Changes to Cargo.toml.
1 2 | [package] name = "wakerizer" | | < > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
[package]
name = "wakerizer"
version = "0.2.0"
edition = "2021"
license = "0BSD"
categories = [ "concurrency", "asynchronous" ]
keywords = [ "async", "future" ]
repository = "https://repos.qrnch.tech/pub/wakerizer"
description = "Helpers for resources that may have multiple concurrent wakers."
rust-version = "1.56"
exclude = [
".fossil-settings",
".efiles",
".fslckout",
"www",
"bacon.toml",
"rustfmt.toml"
]
[dependencies]
parking_lot = { version = "0.12.3" }
rustc-hash = { version = "2.1.1" }
[dev-dependencies]
tokio = { version = "1.44.1", features = [
"macros", "rt", "rt-multi-thread", "time"
] }
[package.metadata.docs.rs]
|
| ︙ | ︙ |
Changes to src/lib.rs.
1 2 3 | //! _wakerizer_ is intended to be used to keep track of multiple `Future`s //! waiting for a single (shared) resource. //! | | | < | < < < < < < | | | < < < < < < < < < < < < < < < < < < < < | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
//! _wakerizer_ is intended to be used to keep track of multiple `Future`s
//! waiting for a single (shared) resource.
//!
//! It can assist in developing behaviors vaguely similar to `Condvar`'s
//! `notify_all()`.
//!
//! # Usage
//! A resource that may be waited on creates and stores a [`Wakers`] object.
//!
//! Each time a `Future` is created that will be waiting for the resource, its
//! `Wakers` spawns a [`Waiter`], which is stored with the `Future`.
//!
//! If the Future's `poll()` function returns `Poll::Pending`, it calls its
//! `Waiter::prime()` to indicate that it is a Future that is actively waiting.
//!
//! Whenever the resource is ready, it can signal waiting futures using
//! [`Wakers::wake_all()`].
use std::{
sync::Arc,
task::{Context, Waker}
};
use parking_lot::Mutex;
use rustc_hash::FxHashMap;
struct Inner {
wake_on_drop: bool,
wakers: FxHashMap<u32, Waker>,
idgen: u32
}
/// A set of wakers that can be used to wake up pending futures.
#[repr(transparent)]
#[derive(Clone)]
pub struct Wakers(Arc<Mutex<Inner>>);
impl Wakers {
#[must_use]
pub fn new() -> Self {
Self::default()
}
/// Make `Wakers` wake all registered [`Waiter`]s when it's dropped.
pub fn wake_on_drop(&self) {
let mut inner = self.0.lock();
inner.wake_on_drop = true;
}
/// Wake all waiting tasks.
pub fn wake_all(&self) {
self
.0
.lock()
.wakers
.drain()
.for_each(|(_, waker)| waker.wake());
}
/// Allocate a new, unprimed, [`Waiter`].
///
/// Call `Waiter::prime()` to "activate" the `Waiter`.
///
|
| ︙ | ︙ | |||
112 113 114 115 116 117 118 |
}
}
impl Default for Wakers {
fn default() -> Self {
let inner = Inner {
wake_on_drop: false,
| | | | | 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 |
}
}
impl Default for Wakers {
fn default() -> Self {
let inner = Inner {
wake_on_drop: false,
wakers: FxHashMap::default(),
idgen: 0
};
Self(Arc::new(Mutex::new(inner)))
}
}
impl Drop for Wakers {
fn drop(&mut self) {
let mut inner = self.0.lock();
if inner.wake_on_drop {
inner.wakers.drain().for_each(|(_, waker)| waker.wake());
}
}
}
/// Representation of a waker in waiting state.
///
/// Instance of this should be created in `Future`'s `poll()` method when
/// returning `Poll::Pending`. The object should be stored in the same object
/// that implements `Future`.
///
/// This ensures that the waker is automatically removed from the collection of
/// wakers when it is dropped.
pub struct Waiter {
sh: Arc<Mutex<Inner>>,
id: Option<u32>
}
impl Waiter {
/// Prime this waiter for waiting for a Waker.
///
/// This function is typically called just before returning `Poll::Pending`.
pub fn prime(&mut self, ctx: &mut Context<'_>) {
|
| ︙ | ︙ | |||
163 164 165 166 167 168 169 |
}
}
impl Drop for Waiter {
fn drop(&mut self) {
let mut g = self.sh.lock();
if let Some(id) = self.id {
| | | 136 137 138 139 140 141 142 143 144 145 146 147 148 |
}
}
impl Drop for Waiter {
fn drop(&mut self) {
let mut g = self.sh.lock();
if let Some(id) = self.id {
g.wakers.remove(&id);
}
}
}
// vim: set ft=rust et sw=2 ts=2 sts=2 cinoptions=2 tw=79 :
|
Changes to tests/basic.rs.
1 2 3 4 |
use std::{
future::Future,
pin::Pin,
sync::{
| < | > | < < < < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
use std::{
future::Future,
pin::Pin,
sync::{
Arc,
atomic::{AtomicBool, Ordering}
},
task::{Context, Poll},
time::Duration
};
use tokio::{task, time};
use wakerizer::{Waiter, Wakers};
#[derive(Default)]
struct Trigger {
state: Arc<AtomicBool>,
wakers: Wakers
}
impl Trigger {
fn trigger(&self) {
self.state.store(true, Ordering::SeqCst);
self.wakers.wake_all();
}
fn waiter(&self) -> TriggerWaiter {
TriggerWaiter {
state: Arc::clone(&self.state),
|
| ︙ | ︙ | |||
75 76 77 78 79 80 81 |
});
let waiter = button.waiter();
let jh3 = task::spawn(async {
waiter.await;
});
| | | 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 |
});
let waiter = button.waiter();
let jh3 = task::spawn(async {
waiter.await;
});
button.trigger();
jh1.await.unwrap();
jh2.await.unwrap();
jh3.await.unwrap();
}
#[tokio::test]
|
| ︙ | ︙ | |||
103 104 105 106 107 108 109 |
let waiter = button.waiter();
let jh3 = task::spawn(async {
waiter.await;
});
time::sleep(Duration::from_millis(100)).await;
| | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 |
let waiter = button.waiter();
let jh3 = task::spawn(async {
waiter.await;
});
time::sleep(Duration::from_millis(100)).await;
button.trigger();
jh1.await.unwrap();
jh2.await.unwrap();
jh3.await.unwrap();
}
// vim: set ft=rust et sw=2 ts=2 sts=2 cinoptions=2 tw=79 :
|
Changes to www/changelog.md.
1 2 3 4 5 6 | # Change Log ⚠️ indicates a breaking change. ## [Unreleased] | | > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | # Change Log ⚠️ indicates a breaking change. ## [Unreleased] [Details](/vdiff?from=wakerizer-0.2.0&to=trunk) ### Added ### Changed ### Removed --- ## [0.2.0] - 2025-04-05 [Details](/vdiff?from=wakerizer-0.1.0&to=wakerizer-0.2.0) ### Changed - Internals: Switch from `IndexMap` to `rustc-hash::FxHasMap`. ### Removed - ⚠️ Removed `wake_one()`, because it had too sharp edges. --- ## [0.1.0] - 2025-04-01 Initial release. |