1use core::cell::UnsafeCell;
28use core::future::Future;
29use core::mem::MaybeUninit;
30use core::pin::Pin;
31use core::task::{Context, Poll};
32
33use crate::waker;
34
35const NO_WAITER: u32 = 0xFFFF_FFFF;
36
37pub struct Channel<T, const N: usize> {
39 buffer: UnsafeCell<[MaybeUninit<T>; N]>,
40 head: crate::sync::atomic::AtomicUsize,
41 tail: crate::sync::atomic::AtomicUsize,
42 taken: crate::sync::atomic::AtomicBool,
45 recv_waiter: crate::sync::atomic::AtomicU32,
47 send_waiter: crate::sync::atomic::AtomicU32,
49}
50
51impl<T, const N: usize> Channel<T, N> {
52 #[cfg(not(loom))]
54 pub const fn new() -> Self {
55 Self {
56 buffer: UnsafeCell::new(unsafe {
57 MaybeUninit::uninit().assume_init()
63 }),
64 head: crate::sync::atomic::AtomicUsize::new(0),
65 tail: crate::sync::atomic::AtomicUsize::new(0),
66 taken: crate::sync::atomic::AtomicBool::new(false),
67 recv_waiter: crate::sync::atomic::AtomicU32::new(NO_WAITER),
68 send_waiter: crate::sync::atomic::AtomicU32::new(NO_WAITER),
69 }
70 }
71
72 #[cfg(loom)]
75 pub fn new() -> Self {
76 Self {
77 buffer: UnsafeCell::new(unsafe {
78 MaybeUninit::uninit().assume_init()
81 }),
82 head: crate::sync::atomic::AtomicUsize::new(0),
83 tail: crate::sync::atomic::AtomicUsize::new(0),
84 taken: crate::sync::atomic::AtomicBool::new(false),
85 recv_waiter: crate::sync::atomic::AtomicU32::new(NO_WAITER),
86 send_waiter: crate::sync::atomic::AtomicU32::new(NO_WAITER),
87 }
88 }
89
90 pub fn split(&'static self) -> Option<(Sender<'static, T, N>, Receiver<'static, T, N>)> {
94 if self.taken.swap(true, crate::sync::atomic::Ordering::AcqRel) {
95 return None;
96 }
97 Some((Sender { chan: self }, Receiver { chan: self }))
98 }
99}
100
101impl<T, const N: usize> Default for Channel<T, N> {
102 fn default() -> Self {
103 Self::new()
104 }
105}
106
107fn wake_waiter(slot: &crate::sync::atomic::AtomicU32) {
108 let w = slot.swap(NO_WAITER, crate::sync::atomic::Ordering::AcqRel);
109 if w != NO_WAITER {
110 waker::wake_task(crate::task::TaskId::from_u16(w as u16));
111 }
112}
113
114fn register_waiter(slot: &crate::sync::atomic::AtomicU32, id: crate::task::TaskId) {
115 slot.store(id.as_u16() as u32, crate::sync::atomic::Ordering::Release);
116}
117
118pub struct Sender<'a, T, const N: usize> {
120 chan: &'a Channel<T, N>,
121}
122
123pub struct Receiver<'a, T, const N: usize> {
125 chan: &'a Channel<T, N>,
126}
127
128impl<'a, T, const N: usize> Sender<'a, T, N> {
129 pub fn try_send(&self, val: T) -> Result<(), T> {
131 let chan = self.chan;
132 let head = chan.head.load(crate::sync::atomic::Ordering::Acquire);
133 let tail = chan.tail.load(crate::sync::atomic::Ordering::Relaxed);
134 let next_tail = (tail + 1) % N;
135
136 if next_tail == head {
137 return Err(val);
138 }
139
140 unsafe {
145 (*chan.buffer.get())[tail].write(val);
146 }
147 chan.tail
148 .store(next_tail, crate::sync::atomic::Ordering::Release);
149 wake_waiter(&chan.recv_waiter);
150 Ok(())
151 }
152
153 pub fn send(&self, val: T) -> SendFut<'_, 'a, T, N> {
158 SendFut {
159 tx: self,
160 val: Some(val),
161 registered: false,
162 }
163 }
164}
165
166impl<'a, T, const N: usize> Receiver<'a, T, N> {
167 pub fn try_recv(&self) -> Option<T> {
169 let chan = self.chan;
170 let head = chan.head.load(crate::sync::atomic::Ordering::Relaxed);
171 let tail = chan.tail.load(crate::sync::atomic::Ordering::Acquire);
172
173 if head == tail {
174 return None;
175 }
176
177 let val = unsafe { (*chan.buffer.get())[head].assume_init_read() };
182 chan.head
183 .store((head + 1) % N, crate::sync::atomic::Ordering::Release);
184 wake_waiter(&chan.send_waiter);
185 Some(val)
186 }
187
188 pub fn recv(&self) -> Recv<'_, 'a, T, N> {
193 Recv {
194 rx: self,
195 registered: false,
196 }
197 }
198}
199
200pub struct SendFut<'b, 'a, T, const N: usize> {
202 tx: &'b Sender<'a, T, N>,
203 val: Option<T>,
204 registered: bool,
208}
209
210impl<'b, 'a, T, const N: usize> SendFut<'b, 'a, T, N> {
211 fn clear_registration(&self) {
212 if self.registered {
213 self.tx
214 .chan
215 .send_waiter
216 .store(NO_WAITER, crate::sync::atomic::Ordering::Release);
217 }
218 }
219}
220
221impl<'b, 'a, T, const N: usize> Drop for SendFut<'b, 'a, T, N> {
222 fn drop(&mut self) {
223 self.clear_registration();
224 }
225}
226
227impl<'b, 'a, T, const N: usize> Future for SendFut<'b, 'a, T, N> {
228 type Output = ();
229
230 fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<()> {
231 let this = unsafe { self.get_unchecked_mut() };
236 let val = this
237 .val
238 .take()
239 .expect("Send future polled after completion");
240
241 match this.tx.try_send(val) {
242 Ok(()) => {
243 this.clear_registration();
244 Poll::Ready(())
245 }
246 Err(v) => {
247 let id = crate::executor::current_task()
248 .expect("Sender::send().await polled outside of a task context");
249 register_waiter(&this.tx.chan.send_waiter, id);
250 this.registered = true;
251
252 match this.tx.try_send(v) {
255 Ok(()) => {
256 this.clear_registration();
257 Poll::Ready(())
258 }
259 Err(v) => {
260 this.val = Some(v);
261 Poll::Pending
262 }
263 }
264 }
265 }
266 }
267}
268
269pub struct Recv<'b, 'a, T, const N: usize> {
271 rx: &'b Receiver<'a, T, N>,
272 registered: bool,
274}
275
276impl<'b, 'a, T, const N: usize> Recv<'b, 'a, T, N> {
277 fn clear_registration(&self) {
278 if self.registered {
279 self.rx
280 .chan
281 .recv_waiter
282 .store(NO_WAITER, crate::sync::atomic::Ordering::Release);
283 }
284 }
285}
286
287impl<'b, 'a, T, const N: usize> Drop for Recv<'b, 'a, T, N> {
288 fn drop(&mut self) {
289 self.clear_registration();
290 }
291}
292
293impl<'b, 'a, T, const N: usize> Future for Recv<'b, 'a, T, N> {
294 type Output = T;
295
296 fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<T> {
297 let this = unsafe { self.get_unchecked_mut() };
300
301 if let Some(v) = this.rx.try_recv() {
302 this.clear_registration();
303 return Poll::Ready(v);
304 }
305
306 let id = crate::executor::current_task()
307 .expect("Receiver::recv().await polled outside of a task context");
308 register_waiter(&this.rx.chan.recv_waiter, id);
309 this.registered = true;
310
311 if let Some(v) = this.rx.try_recv() {
313 this.clear_registration();
314 return Poll::Ready(v);
315 }
316
317 Poll::Pending
318 }
319}
320
321unsafe impl<T: Send, const N: usize> Sync for Channel<T, N> {}
324
325#[cfg(test)]
326mod tests {
327 use super::*;
328
329 #[test]
330 fn send_recv_roundtrip() {
331 crate::kernel_test! {
332 static CHAN: Channel<u32, 8> = Channel::new();
333 let (tx, rx) = CHAN.split().expect("split once");
334
335 assert!(tx.try_send(42).is_ok());
336 assert_eq!(rx.try_recv(), Some(42));
337 assert_eq!(rx.try_recv(), None);
338 }
339 }
340
341 #[test]
342 fn full_channel_blocks_send() {
343 crate::kernel_test! {
344 static CHAN: Channel<u32, 3> = Channel::new(); let (tx, rx) = CHAN.split().expect("split once");
346
347 assert!(tx.try_send(1).is_ok());
348 assert!(tx.try_send(2).is_ok());
349 assert_eq!(tx.try_send(3), Err(3));
350
351 assert_eq!(rx.try_recv(), Some(1));
352 assert!(tx.try_send(3).is_ok());
353 assert_eq!(rx.try_recv(), Some(2));
354 assert_eq!(rx.try_recv(), Some(3));
355 }
356 }
357
358 #[test]
359 fn empty_channel_try_recv_none() {
360 crate::kernel_test! {
361 static CHAN: Channel<u32, 4> = Channel::new();
362 let (_tx, rx) = CHAN.split().expect("split once");
363 assert_eq!(rx.try_recv(), None);
364 }
365 }
366
367 #[test]
368 fn recv_future_ready_when_data_present() {
369 crate::kernel_test! {
370 static CHAN: Channel<u32, 4> = Channel::new();
371 let (tx, rx) = CHAN.split().expect("split once");
372 tx.try_send(7).unwrap();
373
374 let waker = crate::waker::task_waker(crate::task::TaskId::new(0, 0));
375 let mut cx = Context::from_waker(&waker);
376 let mut fut = rx.recv();
377 let pinned = unsafe { Pin::new_unchecked(&mut fut) };
381 assert_eq!(pinned.poll(&mut cx), Poll::Ready(7));
382 }
383 }
384
385 #[test]
386 #[should_panic(expected = "outside of a task context")]
387 fn recv_future_panics_without_task_context_when_empty() {
388 crate::kernel_test! {
389 static CHAN: Channel<u32, 4> = Channel::new();
390 let (_tx, rx) = CHAN.split().expect("split once");
391
392 let waker = crate::waker::task_waker(crate::task::TaskId::new(0, 0));
393 let mut cx = Context::from_waker(&waker);
394 let mut fut = rx.recv();
395 let pinned = unsafe { Pin::new_unchecked(&mut fut) };
398 let _ = pinned.poll(&mut cx);
399 }
400 }
401}