Skip to main content

embassy_hal_internal/
atomic_ring_buffer.rs

1//! Atomic reusable ringbuffer.
2use core::sync::atomic::{AtomicPtr, AtomicUsize, Ordering};
3use core::{ptr, slice};
4
5/// Atomic reusable ringbuffer
6///
7/// This ringbuffer implementation is designed to be stored in a `static`,
8/// therefore all methods take `&self` and not `&mut self`.
9///
10/// It is "reusable": when created it has no backing buffer, you can give it
11/// one with `init` and take it back with `deinit`, and init it again in the
12/// future if needed. This is very non-idiomatic, but helps a lot when storing
13/// it in a `static`.
14///
15/// One concurrent writer and one concurrent reader are supported, even at
16/// different execution priorities (like main and irq).
17pub struct RingBuffer {
18    #[doc(hidden)]
19    pub buf: AtomicPtr<u8>,
20    len: AtomicUsize,
21
22    // start and end wrap at len*2, not at len.
23    // This allows distinguishing "full" and "empty".
24    // full is when start+len == end (modulo len*2)
25    // empty is when start == end
26    //
27    // This avoids having to consider the ringbuffer "full" at len-1 instead of len.
28    // The usual solution is adding a "full" flag, but that can't be made atomic
29    #[doc(hidden)]
30    pub start: AtomicUsize,
31    #[doc(hidden)]
32    pub end: AtomicUsize,
33}
34
35/// A type which can only read from a ring buffer.
36pub struct Reader<'a>(&'a RingBuffer);
37
38/// A type which can only write to a ring buffer.
39pub struct Writer<'a>(&'a RingBuffer);
40
41impl RingBuffer {
42    /// Create a new empty ringbuffer.
43    pub const fn new() -> Self {
44        Self {
45            buf: AtomicPtr::new(core::ptr::null_mut()),
46            len: AtomicUsize::new(0),
47            start: AtomicUsize::new(0),
48            end: AtomicUsize::new(0),
49        }
50    }
51
52    /// Initialize the ring buffer with a buffer.
53    ///
54    /// # Safety
55    /// - The buffer (`buf .. buf+len`) must be valid memory until `deinit` is called.
56    /// - Must not be called concurrently with any other methods.
57    pub unsafe fn init(&self, buf: *mut u8, len: usize) {
58        // Ordering: it's OK to use `Relaxed` because this is not called
59        // concurrently with other methods.
60        self.buf.store(buf, Ordering::Relaxed);
61        self.len.store(len, Ordering::Relaxed);
62        self.start.store(0, Ordering::Relaxed);
63        self.end.store(0, Ordering::Relaxed);
64    }
65
66    /// Deinitialize the ringbuffer.
67    ///
68    /// After calling this, the ringbuffer becomes empty, as if it was
69    /// just created with `new()`.
70    ///
71    /// # Safety
72    /// - Must not be called concurrently with any other methods.
73    pub unsafe fn deinit(&self) {
74        // Ordering: it's OK to use `Relaxed` because this is not called
75        // concurrently with other methods.
76        self.buf.store(ptr::null_mut(), Ordering::Relaxed);
77        self.len.store(0, Ordering::Relaxed);
78        self.start.store(0, Ordering::Relaxed);
79        self.end.store(0, Ordering::Relaxed);
80    }
81
82    /// Create a reader.
83    ///
84    /// # Safety
85    ///
86    /// - Only one reader can exist at a time.
87    /// - Ringbuffer must be initialized.
88    pub unsafe fn reader(&self) -> Reader<'_> {
89        Reader(self)
90    }
91
92    /// Try creating a reader, fails if not initialized.
93    ///
94    /// # Safety
95    ///
96    /// Only one reader can exist at a time.
97    pub unsafe fn try_reader(&self) -> Option<Reader<'_>> {
98        if self.buf.load(Ordering::Relaxed).is_null() {
99            return None;
100        }
101        Some(Reader(self))
102    }
103
104    /// Create a writer.
105    ///
106    /// # Safety
107    ///
108    /// - Only one writer can exist at a time.
109    /// - Ringbuffer must be initialized.
110    pub unsafe fn writer(&self) -> Writer<'_> {
111        Writer(self)
112    }
113
114    /// Try creating a writer, fails if not initialized.
115    ///
116    /// # Safety
117    ///
118    /// Only one writer can exist at a time.
119    pub unsafe fn try_writer(&self) -> Option<Writer<'_>> {
120        if self.buf.load(Ordering::Relaxed).is_null() {
121            return None;
122        }
123        Some(Writer(self))
124    }
125
126    /// Return if buffer is available.
127    pub fn is_available(&self) -> bool {
128        !self.buf.load(Ordering::Relaxed).is_null() && self.len.load(Ordering::Relaxed) != 0
129    }
130
131    /// Return length of buffer.
132    pub fn len(&self) -> usize {
133        self.len.load(Ordering::Relaxed)
134    }
135
136    /// Return number of items available to read.
137    pub fn available(&self) -> usize {
138        let end = self.end.load(Ordering::Relaxed);
139        let len = self.len.load(Ordering::Relaxed);
140        let start = self.start.load(Ordering::Relaxed);
141        if end >= start {
142            end - start
143        } else {
144            2 * len - start + end
145        }
146    }
147
148    /// Check if buffer is full.
149    pub fn is_full(&self) -> bool {
150        let len = self.len.load(Ordering::Relaxed);
151        let start = self.start.load(Ordering::Relaxed);
152        let end = self.end.load(Ordering::Relaxed);
153
154        self.wrap(start + len) == end
155    }
156
157    /// Check if buffer is at least half full.
158    pub fn is_half_full(&self) -> bool {
159        self.available() >= self.len.load(Ordering::Relaxed) / 2
160    }
161
162    /// Check if buffer is empty.
163    pub fn is_empty(&self) -> bool {
164        let start = self.start.load(Ordering::Relaxed);
165        let end = self.end.load(Ordering::Relaxed);
166
167        start == end
168    }
169
170    fn wrap(&self, mut n: usize) -> usize {
171        let len = self.len.load(Ordering::Relaxed);
172
173        if n >= len * 2 {
174            n -= len * 2
175        }
176        n
177    }
178}
179
180impl<'a> Writer<'a> {
181    /// Push data into the buffer in-place.
182    ///
183    /// The closure `f` is called with a free part of the buffer, it must write
184    /// some data to it and return the amount of bytes written.
185    pub fn push(&mut self, f: impl FnOnce(&mut [u8]) -> usize) -> usize {
186        let (p, n) = self.push_buf();
187        let buf = unsafe { slice::from_raw_parts_mut(p, n) };
188        let n = f(buf);
189        self.push_done(n);
190        n
191    }
192
193    /// Push one data byte.
194    ///
195    /// Returns true if pushed successfully.
196    pub fn push_one(&mut self, val: u8) -> bool {
197        let n = self.push(|f| match f {
198            [] => 0,
199            [x, ..] => {
200                *x = val;
201                1
202            }
203        });
204        n != 0
205    }
206
207    /// Get a buffer where data can be pushed to.
208    ///
209    /// Equivalent to [`Self::push_buf`] but returns a slice.
210    pub fn push_slice(&mut self) -> &mut [u8] {
211        let (data, len) = self.push_buf();
212        unsafe { slice::from_raw_parts_mut(data, len) }
213    }
214
215    /// Get up to two buffers where data can be pushed to.
216    ///
217    /// Equivalent to [`Self::push_bufs`] but returns slices.
218    pub fn push_slices(&mut self) -> [&mut [u8]; 2] {
219        let [(d0, l0), (d1, l1)] = self.push_bufs();
220        unsafe { [slice::from_raw_parts_mut(d0, l0), slice::from_raw_parts_mut(d1, l1)] }
221    }
222
223    /// Get a buffer where data can be pushed to.
224    ///
225    /// Write data to the start of the buffer, then call `push_done` with
226    /// however many bytes you've pushed.
227    ///
228    /// The buffer is suitable to DMA to.
229    ///
230    /// If the ringbuf is full, size=0 will be returned.
231    ///
232    /// The buffer stays valid as long as no other `Writer` method is called
233    /// and `init`/`deinit` aren't called on the ringbuf.
234    pub fn push_buf(&mut self) -> (*mut u8, usize) {
235        // Ordering: popping writes `start` last, so we read `start` first.
236        // Read it with Acquire ordering, so that the next accesses can't be reordered up past it.
237        let mut start = self.0.start.load(Ordering::Acquire);
238        let buf = self.0.buf.load(Ordering::Relaxed);
239        let len = self.0.len.load(Ordering::Relaxed);
240        let mut end = self.0.end.load(Ordering::Relaxed);
241
242        let empty = start == end;
243
244        if start >= len {
245            start -= len
246        }
247        if end >= len {
248            end -= len
249        }
250
251        if start == end && !empty {
252            // full
253            return (buf, 0);
254        }
255        let n = if start > end { start - end } else { len - end };
256
257        trace!("  ringbuf: push_buf {:?}..{:?}", end, end + n);
258        (unsafe { buf.add(end) }, n)
259    }
260
261    /// Get up to two buffers where data can be pushed to.
262    ///
263    /// Write data starting at the beginning of the first buffer, then call
264    /// `push_done` with however many bytes you've pushed.
265    ///
266    /// The buffers are suitable to DMA to.
267    ///
268    /// If the ringbuf is full, both buffers will be zero length.
269    /// If there is only area available, the second buffer will be zero length.
270    ///
271    /// The buffer stays valid as long as no other `Writer` method is called
272    /// and `init`/`deinit` aren't called on the ringbuf.
273    pub fn push_bufs(&mut self) -> [(*mut u8, usize); 2] {
274        // Ordering: as per push_buf()
275        let mut start = self.0.start.load(Ordering::Acquire);
276        let buf = self.0.buf.load(Ordering::Relaxed);
277        let len = self.0.len.load(Ordering::Relaxed);
278        let mut end = self.0.end.load(Ordering::Relaxed);
279
280        let empty = start == end;
281
282        if start >= len {
283            start -= len
284        }
285        if end >= len {
286            end -= len
287        }
288
289        if start == end && !empty {
290            // full
291            return [(buf, 0), (buf, 0)];
292        }
293        let n0 = if start > end { start - end } else { len - end };
294        let n1 = if start <= end { start } else { 0 };
295
296        trace!("  ringbuf: push_bufs [{:?}..{:?}, {:?}..{:?}]", end, end + n0, 0, n1);
297        [(unsafe { buf.add(end) }, n0), (buf, n1)]
298    }
299
300    /// Mark n bytes as written and advance the write index.
301    pub fn push_done(&mut self, n: usize) {
302        trace!("  ringbuf: push {:?}", n);
303        let end = self.0.end.load(Ordering::Relaxed);
304
305        // Ordering: write `end` last, with Release ordering.
306        // The ordering ensures no preceding memory accesses (such as writing
307        // the actual data in the buffer) can be reordered down past it, which
308        // will guarantee the reader sees them after reading from `end`.
309        self.0.end.store(self.0.wrap(end + n), Ordering::Release);
310    }
311}
312
313impl<'a> Reader<'a> {
314    /// Pop data from the buffer in-place.
315    ///
316    /// The closure `f` is called with the next data, it must process
317    /// some data from it and return the amount of bytes processed.
318    pub fn pop(&mut self, f: impl FnOnce(&[u8]) -> usize) -> usize {
319        let (p, n) = self.pop_buf();
320        let buf = unsafe { slice::from_raw_parts(p, n) };
321        let n = f(buf);
322        self.pop_done(n);
323        n
324    }
325
326    /// Pop one data byte.
327    ///
328    /// Returns true if popped successfully.
329    pub fn pop_one(&mut self) -> Option<u8> {
330        let mut res = None;
331        self.pop(|f| match f {
332            &[] => 0,
333            &[x, ..] => {
334                res = Some(x);
335                1
336            }
337        });
338        res
339    }
340
341    /// Get a buffer where data can be popped from.
342    ///
343    /// Equivalent to [`Self::pop_buf`] but returns a slice.
344    pub fn pop_slice(&mut self) -> &mut [u8] {
345        let (data, len) = self.pop_buf();
346        unsafe { slice::from_raw_parts_mut(data, len) }
347    }
348
349    /// Get a buffer where data can be popped from.
350    ///
351    /// Read data from the start of the buffer, then call `pop_done` with
352    /// however many bytes you've processed.
353    ///
354    /// The buffer is suitable to DMA from.
355    ///
356    /// If the ringbuf is empty, size=0 will be returned.
357    ///
358    /// The buffer stays valid as long as no other `Reader` method is called
359    /// and `init`/`deinit` aren't called on the ringbuf.
360    pub fn pop_buf(&mut self) -> (*mut u8, usize) {
361        // Ordering: pushing writes `end` last, so we read `end` first.
362        // Read it with Acquire ordering, so that the next accesses can't be reordered up past it.
363        // This is needed to guarantee we "see" the data written by the writer.
364        let mut end = self.0.end.load(Ordering::Acquire);
365        let buf = self.0.buf.load(Ordering::Relaxed);
366        let len = self.0.len.load(Ordering::Relaxed);
367        let mut start = self.0.start.load(Ordering::Relaxed);
368
369        if start == end {
370            return (buf, 0);
371        }
372
373        if start >= len {
374            start -= len
375        }
376        if end >= len {
377            end -= len
378        }
379
380        let n = if end > start { end - start } else { len - start };
381
382        trace!("  ringbuf: pop_buf {:?}..{:?}", start, start + n);
383        (unsafe { buf.add(start) }, n)
384    }
385
386    /// Mark n bytes as read and allow advance the read index.
387    pub fn pop_done(&mut self, n: usize) {
388        trace!("  ringbuf: pop {:?}", n);
389
390        let start = self.0.start.load(Ordering::Relaxed);
391
392        // Ordering: write `start` last, with Release ordering.
393        // The ordering ensures no preceding memory accesses (such as reading
394        // the actual data) can be reordered down past it. This is necessary
395        // because writing to `start` is effectively freeing the read part of the
396        // buffer, which "gives permission" to the writer to write to it again.
397        // Therefore, all buffer accesses must be completed before this.
398        self.0.start.store(self.0.wrap(start + n), Ordering::Release);
399    }
400}
401
402#[cfg(test)]
403mod tests {
404    use super::*;
405
406    #[test]
407    fn push_pop() {
408        let mut b = [0; 4];
409        let rb = RingBuffer::new();
410        unsafe {
411            rb.init(b.as_mut_ptr(), 4);
412
413            assert_eq!(rb.is_empty(), true);
414            assert_eq!(rb.is_half_full(), false);
415            assert_eq!(rb.is_full(), false);
416
417            rb.writer().push(|buf| {
418                assert_eq!(4, buf.len());
419                buf[0] = 1;
420                buf[1] = 2;
421                buf[2] = 3;
422                buf[3] = 4;
423                4
424            });
425
426            assert_eq!(rb.is_empty(), false);
427            assert_eq!(rb.is_half_full(), true);
428            assert_eq!(rb.is_full(), true);
429
430            rb.writer().push(|buf| {
431                // If it's full, we can push 0 bytes.
432                assert_eq!(0, buf.len());
433                0
434            });
435
436            assert_eq!(rb.is_empty(), false);
437            assert_eq!(rb.is_half_full(), true);
438            assert_eq!(rb.is_full(), true);
439
440            rb.reader().pop(|buf| {
441                assert_eq!(4, buf.len());
442                assert_eq!(1, buf[0]);
443                1
444            });
445
446            assert_eq!(rb.is_empty(), false);
447            assert_eq!(rb.is_half_full(), true);
448            assert_eq!(rb.is_full(), false);
449
450            rb.reader().pop(|buf| {
451                assert_eq!(3, buf.len());
452                0
453            });
454
455            assert_eq!(rb.is_empty(), false);
456            assert_eq!(rb.is_half_full(), true);
457            assert_eq!(rb.is_full(), false);
458
459            rb.reader().pop(|buf| {
460                assert_eq!(3, buf.len());
461                assert_eq!(2, buf[0]);
462                assert_eq!(3, buf[1]);
463                2
464            });
465            rb.reader().pop(|buf| {
466                assert_eq!(1, buf.len());
467                assert_eq!(4, buf[0]);
468                1
469            });
470
471            assert_eq!(rb.is_empty(), true);
472            assert_eq!(rb.is_half_full(), false);
473            assert_eq!(rb.is_full(), false);
474
475            rb.reader().pop(|buf| {
476                assert_eq!(0, buf.len());
477                0
478            });
479
480            rb.writer().push(|buf| {
481                assert_eq!(4, buf.len());
482                buf[0] = 10;
483                1
484            });
485
486            assert_eq!(rb.is_empty(), false);
487            assert_eq!(rb.is_half_full(), false);
488            assert_eq!(rb.is_full(), false);
489
490            rb.writer().push(|buf| {
491                assert_eq!(3, buf.len());
492                buf[0] = 11;
493                1
494            });
495
496            assert_eq!(rb.is_empty(), false);
497            assert_eq!(rb.is_half_full(), true);
498            assert_eq!(rb.is_full(), false);
499
500            rb.writer().push(|buf| {
501                assert_eq!(2, buf.len());
502                buf[0] = 12;
503                1
504            });
505
506            assert_eq!(rb.is_empty(), false);
507            assert_eq!(rb.is_half_full(), true);
508            assert_eq!(rb.is_full(), false);
509
510            rb.writer().push(|buf| {
511                assert_eq!(1, buf.len());
512                buf[0] = 13;
513                1
514            });
515
516            assert_eq!(rb.is_empty(), false);
517            assert_eq!(rb.is_half_full(), true);
518            assert_eq!(rb.is_full(), true);
519        }
520    }
521
522    #[test]
523    fn zero_len() {
524        let mut b = [0; 0];
525
526        let rb = RingBuffer::new();
527        unsafe {
528            rb.init(b.as_mut_ptr(), b.len());
529
530            assert_eq!(rb.is_empty(), true);
531            assert_eq!(rb.is_half_full(), true);
532            assert_eq!(rb.is_full(), true);
533
534            rb.writer().push(|buf| {
535                assert_eq!(0, buf.len());
536                0
537            });
538
539            rb.reader().pop(|buf| {
540                assert_eq!(0, buf.len());
541                0
542            });
543        }
544    }
545
546    #[test]
547    fn push_slices() {
548        let mut b = [0; 4];
549        let rb = RingBuffer::new();
550        unsafe {
551            rb.init(b.as_mut_ptr(), 4);
552
553            /* push 3 -> [1 2 3 x] */
554            let mut w = rb.writer();
555            let ps = w.push_slices();
556            assert_eq!(4, ps[0].len());
557            assert_eq!(0, ps[1].len());
558            ps[0][0] = 1;
559            ps[0][1] = 2;
560            ps[0][2] = 3;
561            w.push_done(3);
562            drop(w);
563
564            /* pop 2 -> [x x 3 x] */
565            rb.reader().pop(|buf| {
566                assert_eq!(3, buf.len());
567                assert_eq!(1, buf[0]);
568                assert_eq!(2, buf[1]);
569                assert_eq!(3, buf[2]);
570                2
571            });
572
573            /* push 3 -> [5 6 3 4] */
574            let mut w = rb.writer();
575            let ps = w.push_slices();
576            assert_eq!(1, ps[0].len());
577            assert_eq!(2, ps[1].len());
578            ps[0][0] = 4;
579            ps[1][0] = 5;
580            ps[1][1] = 6;
581            w.push_done(3);
582            drop(w);
583
584            /* buf is now full */
585            let mut w = rb.writer();
586            let ps = w.push_slices();
587            assert_eq!(0, ps[0].len());
588            assert_eq!(0, ps[1].len());
589
590            /* pop 2 -> [5 6 x x] */
591            rb.reader().pop(|buf| {
592                assert_eq!(2, buf.len());
593                assert_eq!(3, buf[0]);
594                assert_eq!(4, buf[1]);
595                2
596            });
597
598            /* should now have one push slice again */
599            let mut w = rb.writer();
600            let ps = w.push_slices();
601            assert_eq!(2, ps[0].len());
602            assert_eq!(0, ps[1].len());
603            drop(w);
604
605            /* pop 2 -> [x x x x] */
606            rb.reader().pop(|buf| {
607                assert_eq!(2, buf.len());
608                assert_eq!(5, buf[0]);
609                assert_eq!(6, buf[1]);
610                2
611            });
612
613            /* should now have two push slices */
614            let mut w = rb.writer();
615            let ps = w.push_slices();
616            assert_eq!(2, ps[0].len());
617            assert_eq!(2, ps[1].len());
618            drop(w);
619
620            /* make sure we exercise all wrap around cases properly */
621            for _ in 0..10 {
622                /* should be empty, push 1 */
623                let mut w = rb.writer();
624                let ps = w.push_slices();
625                assert_eq!(4, ps[0].len() + ps[1].len());
626                w.push_done(1);
627                drop(w);
628
629                /* should have 1 element */
630                let mut w = rb.writer();
631                let ps = w.push_slices();
632                assert_eq!(3, ps[0].len() + ps[1].len());
633                drop(w);
634
635                /* pop 1 */
636                rb.reader().pop(|buf| {
637                    assert_eq!(1, buf.len());
638                    1
639                });
640            }
641        }
642    }
643}