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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
//! Multi-producer, single-consumer channels for sending values between tasks.
//!
//! The module has two flavors. The bounded one ([`channel`]) holds at most a
//! fixed number of messages, and a send waits for room, which is backpressure.
//! The unbounded one ([`unbounded_channel`]) never makes a send wait, so
//! [`UnboundedSender::send`] is an ordinary function that synchronous and
//! asynchronous code can both call. The names, signatures, error types and
//! documented behavior are those of the established async channel API, so code
//! written against that API compiles against these; nothing here needs a
//! runtime, and every wait is a plain [`Waker`](core::task::Waker) handshake.
//!
//! ```
//! use nuclei::sync::mpsc;
//!
//! let (tx, mut rx) = mpsc::channel(8);
//! let senders: Vec<_> = (0..4)
//! .map(|id| {
//! let tx = tx.clone();
//! std::thread::spawn(move || {
//! for n in 0..100 {
//! tx.blocking_send((id, n)).expect("the receiver is still there");
//! }
//! })
//! })
//! .collect();
//! drop(tx);
//!
//! let mut seen = [0; 4];
//! while let Some((id, _n)) = rx.blocking_recv() {
//! seen[id] += 1;
//! }
//! assert_eq!(seen, [100; 4]);
//! for sender in senders {
//! sender.join().unwrap();
//! }
//! ```
//!
//! # Ordering
//!
//! What one sender sends comes out in the order it was sent, as the
//! established API promises. The message queue is a linearizable FIFO queue
//! of cells: a send claims the next cell, and the receiver takes cells in the
//! order they were claimed, so a send that returned before another began
//! comes out first. Values that different senders send at the
//! same time come out in the order their sends claimed cells.
//!
//! # Disconnection
//!
//! When every sender is dropped, no value can be sent. That is the end of the
//! stream: once the buffered values are received, `recv` returns `None`.
//!
//! If the receiver is dropped, its unread values are dropped with it, and
//! every later send fails with an error that holds the value.
//!
//! # Clean shutdown
//!
//! Dropping the receiver loses the values still buffered. For a clean
//! shutdown the receiver calls `close` first, which stops further sends but
//! keeps the buffered values (and any slot a sender reserved before) usable,
//! then receives until `recv` returns `None`.
//!
//! # Weak senders
//!
//! A [`WeakSender`] does not keep the channel open: when only weak senders
//! remain the channel is closed. [`WeakSender::upgrade`] gives a [`Sender`]
//! while one exists. An actor can hold a weak handle to its own mailbox
//! without keeping it alive.
//!
//! # Communicating between sync and async code
//!
//! Every method that is not `async` can be called from any thread. For
//! synchronous code on the receiving or sending end, the `blocking_*` methods
//! park the calling thread until their wait is over. On a nuclei shard they
//! run a nested `block_on` instead, which keeps the shard running its other
//! tasks; do not call them from a task of another runtime, whose thread they
//! block.
//!
//! # Differences from the established API
//!
//! - [`Sender::send_timeout`] waits on nuclei's own timers: on a thread that
//! runs no nuclei shard, the default runtime fires it.
//! - The `blocking_*` methods called from inside a task do not panic: on a
//! nuclei shard they run a nested `block_on`, and inside another runtime's
//! task they block its thread (on `wasm32`, where nothing else can run, a
//! call that would wait forever panics instead).
//! - When the receiver closes, a reservation still waiting gives back the
//! slots set aside for it at the close, where the established API keeps
//! them with the failed wait until its future is dropped. So a closed
//! receiver's drain never waits for a failed reservation to be dropped.
//! - [`Receiver::try_recv`] does not park the thread for a send that is in
//! progress on another thread. Such a value is not in the channel yet, and
//! its sender wakes the receiver when it is; the established API parks the
//! thread until the send finishes.
//! - There is no cooperative-scheduling budget: a receiver that always finds a
//! value never yields.
//!
//! # Progress
//!
//! The message queue is built for its one receiver: a bounded channel's is a
//! ring of cells used lap after lap (a radix directory past 65,536 cells), an
//! unbounded channel's a radix directory of leaves. A send claims the next
//! cell with one fetch-add, finds its segment (in the ring by its position, in
//! the directory by at most one level per ten of a 64-bit position, making a
//! missing node with one compare-and-swap that, lost, leaves another send's),
//! writes its value and marks the cell ready: the push is wait-free. A receive
//! reads the next cell's mark and takes the value, with no read-modify-write
//! and nothing another thread contends for, and never waits for a sender:
//! when the next cell is claimed by a send that has not written it yet, the
//! receive finds nothing for now, registers its waker and returns `Pending`,
//! and that send wakes it once its value is in. A sender the scheduler stops
//! between its claim and its write holds back no one else's value in the
//! radix directory, unless the position right after it is stalled too: the
//! receive takes the ready values past it (within 64 positions), each
//! sender's still in its order, and its own once written. In
//! a bounded channel's ring the values behind it wait until it runs again, as
//! its cell holds their place in the lap; no call waits for it either way.
//!
//! - **Wait-free** (a bounded number of the caller's own atomic steps, whatever
//! other threads do): the accessors (`is_closed`, `len`, `is_empty`,
//! `capacity`, `max_capacity`, the sender counts, `same_channel`), `clone`,
//! `downgrade`, and dropping a sender or weak sender (the last sender's
//! drop also wakes the receiver, a two-step handshake on the waker cell).
//! Registering the receiver's waker is wait-free too, and so is
//! [`UnboundedSender::send`]: its admission is one fetch-add (taken back
//! with one fetch-sub on a closed channel), its push the queue's.
//! - **Lock-free**: every bounded send, `try_send`, reservation and permit
//! send, whose admission is the semaphore's compare-and-swap (exact: it
//! never refuses a free slot);
//! `closed`; `WeakSender::upgrade` (a compare-and-swap loop on the sender
//! count); and `Receiver::close`. A bounded wait that has to queue is
//! lock-free for the reason every wait queue is (see the
//! [parent module](super#progress)): its poll pushes a node, and may serve
//! the queue for one pass plus one for each operation of another thread
//! that lands meanwhile.
//! - **When a waiting bounded send is served** is not a bound on its own
//! calls. Its slot is set aside and granted by whichever thread serves the
//! queue once the slot is free (the receiver taking a value, a permit
//! dropped), so a thread the scheduler stops while it serves the queue
//! delays that grant until it runs again, and a `try_send` fails meanwhile
//! even if the last waiting send has just left. No call waits for it.
//! - **Lock-free**: every receive (`recv`, `recv_many`, `try_recv`,
//! `poll_recv`, `poll_recv_many`), none of which waits for a sender inside
//! the call, and the receiver's drop, which drops every value left and so
//! takes time proportional to them.
//! - A [`Waker`](core::task::Waker) the channel calls is the executor's, and so
//! is what it does; the destructor of a value runs in the call that drops
//! it; and the `blocking_*` methods park the thread until their wait is over,
//! which is what they are for.
//!
//! # Cancel safety
//!
//! `recv`, `recv_many` and `closed` are cancel safe: dropping the future loses
//! nothing. `send` is cancel safe in the sense that a dropped future sent
//! nothing, but it drops the value it held; `reserve` and its relatives hold no
//! slot when dropped, and a dropped `reserve_owned` also drops its sender.
//!
//! # Fairness
//!
//! The bounded channel serves waiting sends and reservations strictly in the
//! order they began to wait, as the established API does. Slots that come
//! free are set aside for the oldest waiting request until it has all it
//! asked for, so a `reserve_many(n)` is not starved by smaller requests and
//! nothing behind it is served first; a `try_send` or `try_reserve` never
//! takes a slot while a request waits. Dropping a waiting future gives up its
//! place and passes on whatever was set aside or granted to it, so no slot
//! and no wakeup is lost. The unbounded channel never waits, so it has no
//! order to keep.
pub use ;
pub use ;
pub use Receiver;
pub use ;