Skip to main content

nuclei/sync/local/
mod.rs

1//! Synchronization primitives for the tasks of one shard.
2//!
3//! Everything here is for tasks that share one shard ([`task::spawn_local`](crate::task::spawn_local),
4//! or the future `block_on` runs): the state sits in `Rc`s and plain cells,
5//! so the types are `!Send` and `!Sync`, and no path executes an atomic
6//! instruction or a fence. That makes them cheaper than their atomic
7//! twins in [`sync`](crate::sync): CI counts the instructions of a message
8//! and of a one-shot reply on both (`ci/op_budget.txt`). The names and
9//! signatures mirror the atomic ones, so
10//! code switches by changing the path: [`mpsc`] for
11//! [`sync::mpsc`](crate::sync::mpsc), [`oneshot`] for
12//! [`sync::oneshot`](crate::sync::oneshot), [`Semaphore`] for
13//! [`sync::Semaphore`](crate::sync::Semaphore) and [`Mutex`] for
14//! [`sync::Mutex`](crate::sync::Mutex). The errors are the atomic ones.
15//!
16//! ```compile_fail
17//! fn send<T: Send>(_: T) {}
18//! send(nuclei::sync::local::Mutex::new(0u8));
19//! ```
20//!
21//! # Fairness
22//!
23//! Sends on a full bounded channel, acquires of the semaphore and locks of
24//! the mutex are served strictly in arrival order, with no barging: permits
25//! that come free are kept for the front waiter until its whole request
26//! fits, and `try_` forms fail while anyone waits.
27//!
28//! # Cancel safety
29//!
30//! Dropping any future of this module at any await loses no value, no
31//! permit and no wakeup, and leaks nothing: a waiting future gives up its
32//! place in line (the next waiter is served if it was the front), and one
33//! that was already granted its permits or the lock passes them on.
34//!
35//! # Cooperative scheduling
36//!
37//! The budget of [`task::coop`](crate::task::coop) applies as for the atomic
38//! twins: a receive, an acquire or a lock that completes spends one
39//! operation of the task's budget, and a bounded send or reservation that
40//! completes at its first attempt does too. A wait that queued and was
41//! granted spends nothing. The `try_` forms never spend.
42//!
43//! # Interior mutability
44//!
45//! The module keeps one rule. A cell is borrowed only inside one
46//! non-reentrant step, and nothing that can run user code (a
47//! [`Waker::wake`](core::task::Waker::wake), a value's `Drop`, a waker's
48//! clone) runs while any of them is borrowed: the waker or the values are
49//! taken out first, the borrow ends, and then they are woken or dropped.
50//! After a wake the state is read again; no borrow is reused.
51
52pub mod mpsc;
53mod mutex;
54pub mod oneshot;
55mod semaphore;
56mod waiters;
57
58pub use mutex::{Lock, Mutex, MutexGuard};
59pub use semaphore::{Acquire, Semaphore, SemaphorePermit};