dtact_util/sync/
broadcast.rs1use super::wait_queue::WaitQueue;
7use std::cell::UnsafeCell;
8use std::mem::MaybeUninit;
9use std::sync::Arc;
10use std::sync::atomic::{AtomicU64, AtomicUsize, Ordering};
11use std::task::{Context, Poll};
12
13#[repr(align(64))]
15struct Slot<T> {
16 seq: AtomicU64,
20 value: UnsafeCell<MaybeUninit<T>>,
22}
23
24unsafe impl<T: Send> Send for Slot<T> {}
25unsafe impl<T: Sync> Sync for Slot<T> {}
26
27impl<T> Slot<T> {
28 const fn new() -> Self {
29 Self {
30 seq: AtomicU64::new(u64::MAX),
31 value: UnsafeCell::new(MaybeUninit::uninit()),
32 }
33 }
34}
35
36#[repr(align(64))]
37struct Shared<T> {
38 slots: Box<[Slot<T>]>,
40 capacity: usize,
41 next_seq: AtomicU64,
42 sender_count: AtomicUsize,
43 wait: WaitQueue,
44}
45
46unsafe impl<T: Send> Send for Shared<T> {}
47unsafe impl<T: Sync> Sync for Shared<T> {}
48
49#[must_use]
51#[inline]
52pub fn channel<T: Clone>(capacity: usize) -> (Sender<T>, Receiver<T>) {
53 let capacity = capacity.max(1);
54
55 let mut slots = Vec::with_capacity(capacity);
56 for _ in 0..capacity {
57 slots.push(Slot::new());
58 }
59
60 let shared = Arc::new(Shared {
61 slots: slots.into_boxed_slice(),
62 capacity,
63 next_seq: AtomicU64::new(0),
64 sender_count: AtomicUsize::new(1),
65 wait: WaitQueue::new(),
66 });
67
68 let receiver = Receiver {
69 shared: shared.clone(),
70 next_seq: 0,
71 };
72
73 (Sender { shared }, receiver)
74}
75
76#[repr(align(64))]
78pub struct Sender<T> {
79 shared: Arc<Shared<T>>,
80}
81
82impl<T> Clone for Sender<T> {
83 #[inline(always)]
84 fn clone(&self) -> Self {
85 self.shared.sender_count.fetch_add(1, Ordering::AcqRel);
86 Self {
87 shared: self.shared.clone(),
88 }
89 }
90}
91
92impl<T> Drop for Sender<T> {
93 #[inline(always)]
94 fn drop(&mut self) {
95 if self.shared.sender_count.fetch_sub(1, Ordering::AcqRel) == 1 {
96 self.shared.wait.wake_all();
97 }
98 }
99}
100
101impl<T: Clone> Sender<T> {
102 #[inline(always)]
111 pub fn send(&self, value: T) -> Result<(), SendError<T>> {
112 if self.receiver_count() == 0 {
113 return Err(SendError(value));
114 }
115
116 let seq = self.shared.next_seq.fetch_add(1, Ordering::Relaxed);
117 let idx = (seq as usize) % self.shared.capacity;
118 let slot = &self.shared.slots[idx];
119
120 slot.seq.store(u64::MAX - 1, Ordering::Release);
124
125 unsafe {
127 let ptr = slot.value.get();
128 if seq >= self.shared.capacity as u64 {
130 std::ptr::drop_in_place((*ptr).as_mut_ptr());
131 }
132 std::ptr::write((*ptr).as_mut_ptr(), value);
133 }
134
135 slot.seq.store(seq, Ordering::Release);
137
138 if self.shared.wait.has_waiters() {
139 self.shared.wait.wake_all();
140 }
141
142 Ok(())
143 }
144
145 #[must_use]
148 #[inline(always)]
149 pub fn receiver_count(&self) -> usize {
150 Arc::strong_count(&self.shared)
151 .saturating_sub(self.shared.sender_count.load(Ordering::Acquire))
152 }
153}
154
155#[repr(align(64))]
157pub struct Receiver<T> {
158 shared: Arc<Shared<T>>,
159 next_seq: u64,
160}
161
162#[allow(clippy::non_send_fields_in_send_ty)]
163unsafe impl<T: Send> Send for Receiver<T> {}
164unsafe impl<T: Send> Sync for Receiver<T> {}
165
166impl<T> Clone for Receiver<T> {
167 #[inline(always)]
168 fn clone(&self) -> Self {
169 Self {
170 shared: self.shared.clone(),
171 next_seq: self.next_seq,
172 }
173 }
174}
175
176impl<T: Clone> Receiver<T> {
177 #[inline(always)]
185 pub async fn recv(&mut self) -> Result<T, RecvError> {
186 std::future::poll_fn(|cx| self.poll_recv(cx)).await
187 }
188
189 #[inline]
190 fn poll_recv(&mut self, cx: &Context<'_>) -> Poll<Result<T, RecvError>> {
191 if let Some(result) = self.try_recv_one() {
192 return Poll::Ready(result);
193 }
194 if self.is_closed() {
195 return Poll::Ready(self.try_recv_one().unwrap_or(Err(RecvError::Closed)));
196 }
197 let token = self.shared.wait.register(cx.waker());
198 if let Some(result) = self.try_recv_one() {
199 self.shared.wait.cancel(token);
200 return Poll::Ready(result);
201 }
202 if self.is_closed() {
203 let result = self.try_recv_one().unwrap_or(Err(RecvError::Closed));
204 self.shared.wait.cancel(token);
205 return Poll::Ready(result);
206 }
207 Poll::Pending
208 }
209
210 #[inline]
211 fn try_recv_one(&mut self) -> Option<Result<T, RecvError>> {
212 let idx = (self.next_seq as usize) % self.shared.capacity;
213 let slot = &self.shared.slots[idx];
214
215 let slot_seq = slot.seq.load(Ordering::Acquire);
216
217 if slot_seq == u64::MAX || slot_seq == u64::MAX - 1 {
220 return None;
221 }
222
223 match self.next_seq.cmp(&slot_seq) {
224 std::cmp::Ordering::Equal => {
225 let cloned_val = unsafe {
227 let ptr = slot.value.get();
228 (*ptr).assume_init_ref().clone()
229 };
230
231 if slot.seq.load(Ordering::Acquire) != slot_seq {
234 return Some(Err(RecvError::Lagged(1)));
235 }
236
237 self.next_seq += 1;
238 Some(Ok(cloned_val))
239 }
240 std::cmp::Ordering::Less => {
241 let skipped = slot_seq - self.next_seq;
242 self.next_seq = slot_seq;
243 Some(Err(RecvError::Lagged(skipped)))
244 }
245 std::cmp::Ordering::Greater => {
246 None }
248 }
249 }
250
251 #[inline(always)]
252 fn is_closed(&self) -> bool {
253 self.shared.sender_count.load(Ordering::Acquire) == 0
254 }
255}
256
257impl<T> Drop for Shared<T> {
258 #[inline(always)]
259 fn drop(&mut self) {
260 let next_seq = self.next_seq.load(Ordering::Acquire);
261 let initialized_elements = next_seq.min(self.capacity as u64) as usize;
263 for i in 0..initialized_elements {
264 unsafe {
265 let ptr = self.slots[i].value.get();
266 std::ptr::drop_in_place((*ptr).as_mut_ptr());
267 }
268 }
269 }
270}
271
272#[derive(Debug, Clone, Copy, PartialEq, Eq)]
275#[repr(align(64))]
276pub struct SendError<T>(pub T);
277
278impl<T> std::fmt::Display for SendError<T> {
279 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
280 f.write_str("broadcast channel has no receivers")
281 }
282}
283
284impl<T: std::fmt::Debug> std::error::Error for SendError<T> {}
285
286#[derive(Debug, Clone, Copy, PartialEq, Eq)]
288#[repr(align(64))]
289pub enum RecvError {
290 Lagged(u64),
295 Closed,
298}
299
300impl std::fmt::Display for RecvError {
301 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
302 match self {
303 Self::Lagged(n) => write!(f, "receiver lagged behind by {n} messages"),
304 Self::Closed => f.write_str("channel closed: every sender dropped"),
305 }
306 }
307}
308
309impl std::error::Error for RecvError {}