Skip to main content

kernel/collections/
ring_buffer.rs

1// Licensed under the Apache License, Version 2.0 or the MIT License.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3// Copyright Tock Contributors 2022.
4
5//! Implementation of a ring buffer.
6
7use crate::collections::queue;
8use core::mem::MaybeUninit;
9
10/// Queue implementation based on a contiguous buffer.
11///
12/// The buffer is assumed to be uninitialized when the [`RingBuffer`] is
13/// created. This can be safely created using uninitialized memory for the ring.
14pub struct RingBuffer<'a, T: Copy + 'a> {
15    /// Array of elements `T`. The buffer does not need to have initialized
16    /// elements `T`. The `RingBuffer` assumes that any element not tracked in
17    /// the ring based on head and tail are not initialized.
18    ring: &'a mut [MaybeUninit<T>],
19    head: usize,
20    tail: usize,
21}
22
23impl<'a, T: Copy> RingBuffer<'a, T> {
24    /// Create a [`RingBuffer`].
25    ///
26    /// The provided `ring` is assumed to be uninitialized and the ring starts
27    /// empty.
28    pub fn new(ring: &'a mut [MaybeUninit<T>]) -> RingBuffer<'a, T> {
29        RingBuffer {
30            head: 0,
31            tail: 0,
32            ring,
33        }
34    }
35
36    /// Returns the number of elements that can be enqueued until the ring buffer is full.
37    pub fn available_len(&self) -> usize {
38        // The maximum capacity of the queue is ring.len - 1, because head == tail for the empty
39        // queue.
40        self.ring.len().saturating_sub(1 + queue::Queue::len(self))
41    }
42
43    /// Returns up to 2 slices that together form the contents of the ring buffer.
44    ///
45    /// Returns:
46    /// - `(None, None)` if the buffer is empty.
47    /// - `(Some(slice), None)` if the head is before the tail (therefore all the contents is
48    /// contiguous).
49    /// - `(Some(left), Some(right))` if the head is after the tail. In that case, the logical
50    /// contents of the buffer is `[left, right].concat()` (although physically the "left" slice is
51    /// stored after the "right" slice).
52    pub fn as_slices(&'a self) -> (Option<&'a [T]>, Option<&'a [T]>) {
53        // SAFETY: Reinterprets &[MaybeUninit<T>] as &[T]. MaybeUninit<T> has the same layout as
54        // T, and every element in the returned slice falls within [head, tail) which has been
55        // written by enqueue/push, so reading those elements as T is valid.
56        let assume_init = |s: &[MaybeUninit<T>]| -> &[T] {
57            unsafe { core::slice::from_raw_parts(s.as_ptr().cast::<T>(), s.len()) }
58        };
59
60        if self.head < self.tail {
61            (Some(assume_init(&self.ring[self.head..self.tail])), None)
62        } else if self.head > self.tail {
63            let (left, right) = self.ring.split_at(self.head);
64            (
65                Some(assume_init(right)),
66                if self.tail == 0 {
67                    None
68                } else {
69                    Some(assume_init(&left[..self.tail]))
70                },
71            )
72        } else {
73            (None, None)
74        }
75    }
76
77    /// Check if `index` into the internal `ring` contains a valid element
78    /// stored in the [`RingBuffer`].
79    fn is_valid(&self, index: usize) -> bool {
80        let capacity = self.ring.len();
81        let position_in_ring = (index + capacity - self.head) % capacity;
82
83        // Check if the position in the ring of `index` is not actually within
84        // the populated ring holding valid elements. If so, return true.
85        // Otherwise, return false.
86        position_in_ring < queue::Queue::len(self)
87    }
88
89    /// Get the element stored at `index` in the `ring` if there is a valid
90    /// element at that index.
91    fn get_internal(&self, index: usize) -> Option<T> {
92        // Check if the position in the ring of `index` is not actually within
93        // the populated ring holding valid elements. If so, this `get()` fails
94        // and we return `None`.
95        if !self.is_valid(index) {
96            None
97        } else {
98            let element = self.ring.get(index);
99            element.map(|e| {
100                // # Safety
101                //
102                // It is safe to read the element from this location in the ring and
103                // assume it is initialized because we verified that the index is
104                // within the populated elements of the ring. Our invariant is that
105                // any index with head and tail _must_ be initialized.
106                unsafe { e.assume_init() }
107            })
108        }
109    }
110
111    /// Get a reference to the element stored at `index` in the `ring` if there
112    /// is a valid element at that index.
113    fn get_internal_ref(&self, index: usize) -> Option<&T> {
114        // Check if the position in the ring of `index` is not actually within
115        // the populated ring holding valid elements. If so, this `get()` fails
116        // and we return `None`.
117        if !self.is_valid(index) {
118            None
119        } else {
120            let element = self.ring.get(index);
121            element.map(|e| {
122                // # Safety
123                //
124                // It is safe to read the element from this location in the ring and
125                // assume it is initialized because we verified that the index is
126                // within the populated elements of the ring. Our invariant is that
127                // any index with head and tail _must_ be initialized.
128                unsafe { e.assume_init_ref() }
129            })
130        }
131    }
132}
133
134impl<T: Copy> queue::Queue<T> for RingBuffer<'_, T> {
135    fn has_elements(&self) -> bool {
136        self.head != self.tail
137    }
138
139    fn is_full(&self) -> bool {
140        self.head == ((self.tail + 1) % self.ring.len())
141    }
142
143    fn len(&self) -> usize {
144        if self.tail > self.head {
145            self.tail - self.head
146        } else if self.tail < self.head {
147            (self.ring.len() - self.head) + self.tail
148        } else {
149            // head equals tail, length is zero
150            0
151        }
152    }
153
154    fn enqueue(&mut self, val: T) -> bool {
155        if self.is_full() {
156            // Incrementing tail will overwrite head
157            false
158        } else {
159            self.ring[self.tail].write(val);
160            self.tail = (self.tail + 1) % self.ring.len();
161            true
162        }
163    }
164
165    fn push(&mut self, val: T) -> Option<T> {
166        let result = if self.is_full() {
167            let old = self.get_internal(self.head);
168            self.head = (self.head + 1) % self.ring.len();
169            old
170        } else {
171            None
172        };
173
174        self.ring[self.tail].write(val);
175        self.tail = (self.tail + 1) % self.ring.len();
176        result
177    }
178
179    fn dequeue(&mut self) -> Option<T> {
180        if self.has_elements() {
181            let val = self.get_internal(self.head);
182            self.head = (self.head + 1) % self.ring.len();
183            val
184        } else {
185            None
186        }
187    }
188
189    /// Finds the first element for which the provided closure returns `true`.
190    ///
191    /// This walks the ring buffer and, upon finding a matching element, returns a
192    /// reference to it.
193    fn find_first_matching<F>(&mut self, f: F) -> Option<&T>
194    where
195        F: Fn(&T) -> bool,
196    {
197        let len = self.ring.len();
198        let mut slot = self.head;
199        while slot != self.tail {
200            if let Some(e) = self.get_internal_ref(slot) {
201                if f(e) {
202                    return Some(e);
203                }
204                slot = (slot + 1) % len;
205            }
206        }
207        None
208    }
209
210    /// Removes the first element for which the provided closure returns `true`.
211    ///
212    /// This walks the ring buffer and, upon finding a matching element, removes
213    /// it. It then shifts all subsequent elements forward (filling the hole
214    /// created by removing the element).
215    ///
216    /// If an element was removed, this function returns it as `Some(elem)`.
217    fn remove_first_matching<F>(&mut self, f: F) -> Option<T>
218    where
219        F: Fn(&T) -> bool,
220    {
221        let len = self.ring.len();
222        let mut slot = self.head;
223        while slot != self.tail {
224            if let Some(e) = self.get_internal_ref(slot) {
225                if f(e) {
226                    // This is the desired element, remove it and return it.
227                    let val = self.get_internal(slot);
228
229                    let mut next_slot = (slot + 1) % len;
230                    // Move everything past this element forward in the ring.
231                    while next_slot != self.tail {
232                        if let Some(to_move) = self.get_internal(next_slot) {
233                            self.ring[slot].write(to_move);
234                            slot = next_slot;
235                            next_slot = (next_slot + 1) % len;
236                        }
237                    }
238                    self.tail = slot;
239                    return val;
240                }
241                slot = (slot + 1) % len;
242            }
243        }
244        None
245    }
246
247    fn empty(&mut self) {
248        self.head = 0;
249        self.tail = 0;
250    }
251
252    fn retain<F>(&mut self, mut f: F)
253    where
254        F: FnMut(&T) -> bool,
255    {
256        let len = self.ring.len();
257        // Index over the elements before the retain operation.
258        let mut src = self.head;
259        // Index over the retained elements.
260        let mut dst = self.head;
261
262        while src != self.tail {
263            if let Some(e) = self.get_internal_ref(src) {
264                if f(e) {
265                    // When the predicate is true, move the current element to the
266                    // destination if needed, and increment the destination index.
267                    if src != dst {
268                        if let Some(to_move) = self.get_internal(src) {
269                            self.ring[dst].write(to_move);
270                        }
271                    }
272                    dst = (dst + 1) % len;
273                }
274                src = (src + 1) % len;
275            }
276        }
277
278        self.tail = dst;
279    }
280}
281
282#[cfg(test)]
283mod test {
284    use super::super::queue::Queue;
285    use super::RingBuffer;
286    use core::mem::MaybeUninit;
287
288    #[test]
289    fn test_enqueue_dequeue() {
290        const LEN: usize = 10;
291        let mut ring: [MaybeUninit<usize>; LEN] = [MaybeUninit::uninit(); LEN];
292        let mut buf = RingBuffer::new(&mut ring);
293
294        for _ in 0..2 * LEN {
295            assert!(buf.enqueue(42));
296            assert_eq!(buf.len(), 1);
297            assert!(buf.has_elements());
298
299            assert_eq!(buf.dequeue(), Some(42));
300            assert_eq!(buf.len(), 0);
301            assert!(!buf.has_elements());
302        }
303    }
304
305    #[test]
306    fn test_push() {
307        const LEN: usize = 10;
308        const MAX: usize = 100;
309        let mut ring: [MaybeUninit<usize>; LEN + 1] = [MaybeUninit::uninit(); LEN + 1];
310        let mut buf = RingBuffer::new(&mut ring);
311
312        for i in 0..LEN {
313            assert_eq!(buf.len(), i);
314            assert!(!buf.is_full());
315            assert_eq!(buf.push(i), None);
316            assert!(buf.has_elements());
317        }
318
319        for i in LEN..MAX {
320            assert!(buf.is_full());
321            assert_eq!(buf.push(i), Some(i - LEN));
322        }
323
324        for i in 0..LEN {
325            assert!(buf.has_elements());
326            assert_eq!(buf.len(), LEN - i);
327            assert_eq!(buf.dequeue(), Some(MAX - LEN + i));
328            assert!(!buf.is_full());
329        }
330
331        assert!(!buf.has_elements());
332    }
333
334    // Enqueue integers 1 <= n < len, checking that it succeeds and that the
335    // queue is full at the end.
336    // See std::iota in C++.
337    fn enqueue_iota(buf: &mut RingBuffer<usize>, len: usize) {
338        for i in 1..len {
339            assert!(!buf.is_full());
340            assert!(buf.enqueue(i));
341            assert!(buf.has_elements());
342            assert_eq!(buf.len(), i);
343        }
344
345        assert!(buf.is_full());
346        assert!(!buf.enqueue(0));
347        assert!(buf.has_elements());
348    }
349
350    // Dequeue all elements, expecting integers 1 <= n < len, checking that the
351    // queue is empty at the end.
352    // See std::iota in C++.
353    fn dequeue_iota(buf: &mut RingBuffer<usize>, len: usize) {
354        for i in 1..len {
355            assert!(buf.has_elements());
356            assert_eq!(buf.len(), len - i);
357            assert_eq!(buf.dequeue(), Some(i));
358            assert!(!buf.is_full());
359        }
360
361        assert!(!buf.has_elements());
362        assert_eq!(buf.len(), 0);
363    }
364
365    // Move the head by `count` elements, by enqueueing/dequeueing `count`
366    // times an element.
367    // This assumes an empty queue at the beginning, and yields an empty queue.
368    fn move_head(buf: &mut RingBuffer<usize>, count: usize) {
369        assert!(!buf.has_elements());
370        assert_eq!(buf.len(), 0);
371
372        for _ in 0..count {
373            assert!(buf.enqueue(0));
374            assert_eq!(buf.dequeue(), Some(0));
375        }
376
377        assert!(!buf.has_elements());
378        assert_eq!(buf.len(), 0);
379    }
380
381    #[test]
382    fn test_fill_once() {
383        const LEN: usize = 10;
384        let mut ring: [MaybeUninit<usize>; LEN] = [MaybeUninit::uninit(); LEN];
385        let mut buf = RingBuffer::new(&mut ring);
386
387        assert!(!buf.has_elements());
388        assert_eq!(buf.len(), 0);
389
390        enqueue_iota(&mut buf, LEN);
391        dequeue_iota(&mut buf, LEN);
392    }
393
394    #[test]
395    fn test_refill() {
396        const LEN: usize = 10;
397        let mut ring: [MaybeUninit<usize>; LEN] = [MaybeUninit::uninit(); LEN];
398        let mut buf = RingBuffer::new(&mut ring);
399
400        for _ in 0..10 {
401            enqueue_iota(&mut buf, LEN);
402            dequeue_iota(&mut buf, LEN);
403        }
404    }
405
406    #[test]
407    fn test_retain() {
408        const LEN: usize = 10;
409        let mut ring: [MaybeUninit<usize>; LEN] = [MaybeUninit::uninit(); LEN];
410        let mut buf = RingBuffer::new(&mut ring);
411
412        move_head(&mut buf, LEN - 2);
413        enqueue_iota(&mut buf, LEN);
414
415        buf.retain(|x| x % 2 == 1);
416        assert_eq!(buf.len(), LEN / 2);
417
418        assert_eq!(buf.dequeue(), Some(1));
419        assert_eq!(buf.dequeue(), Some(3));
420        assert_eq!(buf.dequeue(), Some(5));
421        assert_eq!(buf.dequeue(), Some(7));
422        assert_eq!(buf.dequeue(), Some(9));
423        assert_eq!(buf.dequeue(), None);
424    }
425}
426
427// ===== Flux code ========
428// Flux by-default checks:
429// 1. There are no division-by-zero errors
430// 2. There are no array bounds violations
431//
432// This spec is sufficient to prove the above two properties for RingBuffer,
433// as well as to prove some related, but stronger, well-formedness properties about RingBuffer
434// (e.g., indexes into the RingBuffer are always valid)
435//
436// If any of these properties could be violated either in the RingBuffer implementation or how it
437// is used anywhere in Tock, Flux will raise an error.
438#[cfg(feature = "flux")]
439mod flux_specs {
440    // Prelude: Here we provide some specifications for methods/types in the core library.
441    // This allows Flux to make use of these specs for proving useful things about RingBuffer.
442    // Generally, these specs are per-project---if we verified many modules in
443    // Tock, there would only be 1 centralized set of these specs for all of Tock.
444    #[flux_rs::extern_spec]
445    impl<T> [T] {
446        // Need to tell Flux what slice.len() does
447        #[flux_rs::sig(fn(&[T][@len]) -> usize[len])]
448        fn len(v: &[T]) -> usize;
449
450        // Need to tell Flux what slice.split_at_mut() does (for our tests)
451        #[flux_rs::sig(fn(&mut [T][@len], usize[@mid]) -> (&mut [T][mid], &mut [T][len - mid]))]
452        fn split_at_mut(v: &mut [T], mid: usize) -> (&mut [T], &mut [T]);
453    }
454
455    // Need to tell Flux what an Option<T> is:
456    // Here, we refine Option<T> with a bool, denoting whether it is `Some` or `None`
457    #[flux_rs::extern_spec]
458    #[flux_rs::refined_by(b: bool)]
459    enum Option<T> {
460        #[variant(Option<T>[false])]
461        None,
462        #[variant({T} -> Option<T>[true])]
463        Some(T),
464    }
465
466    // ======= RingBuffer spec ===========
467    #[allow(unused_imports)]
468    use crate::collections::list::ListIterator;
469    use crate::collections::queue::Queue;
470    use crate::collections::ring_buffer::RingBuffer;
471    use core::mem::MaybeUninit;
472
473    #[flux::specs {
474        // Specify well-formedness for RingBuffer<T>.
475        // A well-formed RingBuffer has an internal slice (`ring`) that can store at least 1 element, and
476        // a `head` and `tail` index, each of which must be less than the length of the internal slice.
477        // This ensures that all indices `ring[head]` and `ring[tail]` are valid.
478        #[refined_by(ring_len: int, hd: int, tl: int)]
479        struct RingBuffer<T> {
480            ring: {&mut [MaybeUninit<T>][ring_len] | ring_len > 0},
481            head: {usize[hd] | hd < ring_len},
482            tail: {usize[tl] | tl < ring_len},
483        }
484
485        impl RingBuffer<T> {
486            // A simple function-level spec for the RingBuffer<T> constructor.
487            //
488            // It has a precondition that the input slice is length > 1, so
489            // every time RingBuffer::new() is called (throughout Tock),
490            // Flux will ensure the slice passed in has length > 1.
491            //
492            // It also has a postcondition that the output RingBuffer has a head and tail of zero.
493            // Flux will check the implementation of `new` to ensure this is true.
494            //
495            // Design note: This contract has the strongest possible postcondition (head == 0 and tail == 0),
496            // but we could also make the postcondition something "weaker" like `result.head == result.tail`.
497            // Weaker vs stronger contracts is a design decision: it is easier to prove that a weak contract
498            // holds in the implementation, but it lets you prove less in the rest of Tock (e.g., if there was code
499            // that was only safe if head/tail was 0 after it called new, we could prove its safety only with the stronger contract).
500            fn new({&mut [MaybeUninit<T>][@ring_len] | ring_len > 0}) -> RingBuffer<T>[ring_len, 0, 0];
501        }
502
503        impl Queue<T> for RingBuffer<T> {
504            // These specs of the form: `(self: RingBuffer) ensures RingBuffer`
505            // are present to compensate for a current technical limitation of Flux,
506            // and should be gone in the near future.
507            fn empty(self: &mut RingBuffer<T>[@old])
508                ensures self: RingBuffer<T>;
509
510            fn enqueue(self: &mut RingBuffer<T>, val: T) -> bool
511                ensures self: RingBuffer<T>;
512
513            fn push(self: &mut RingBuffer<T>, val: T) -> Option<T>
514                ensures self: RingBuffer<T>;
515
516            fn dequeue(self: &mut RingBuffer<T>) -> Option<T>
517                ensures self: RingBuffer<T>;
518
519            fn remove_first_matching<F>(self: &mut RingBuffer<T>, _) -> Option<T>
520                ensures self: RingBuffer<T>;
521
522            fn retain<F>(self: &mut RingBuffer<T>, _)
523                ensures self: RingBuffer<T>;
524        }
525
526        impl core::iter::Iterator for ListIterator<T> {
527            fn next(self: &mut ListIterator<T>) -> Option<&T>
528                ensures self: ListIterator<T>;
529        }
530
531    }]
532    const _: () = ();
533
534    // ========= Flux tests ==============
535    // These functions will fail verification, and demonstrate the sorts of
536    // errors that our RingBuffer spec protects us against. Specifically:
537    // 1. Bad usage of the RingBuffer API that leads to kernel panics
538    // 2. Bad implementation of the RingBuffer API that leads to kernel panics
539
540    // 1. Flux will prevent Tock from using the RingBuffer API incorrectly,
541    // leading to panics
542    #[allow(dead_code)]
543    #[flux_rs::should_fail]
544    fn bad_split_into_ringbuffers<'a, T: Copy>(
545        buf: &'a mut [MaybeUninit<T>],
546        output_len: usize,
547    ) -> (RingBuffer<'a, T>, RingBuffer<'a, T>) {
548        // If `output_len` is `0` or `buf.len()`, then `output_ringbuf`
549        // or `internal_ringbuf` will have a length of `0`.
550        // This is bad, because if the `len` of a RingBuffer is `0`,
551        // then functions like `is_full` will panic.
552        let (output_buf, internal_buf) = buf.split_at_mut(output_len);
553        let output_ringbuf = RingBuffer::new(output_buf);
554        let internal_ringbuf = RingBuffer::new(internal_buf);
555        (output_ringbuf, internal_ringbuf)
556    }
557
558    // 2. Here, Flux will prevent RingBuffer implementations from panicing via
559    // out-of-bounds memory access or divide by zero.
560    #[allow(dead_code)]
561    #[flux_rs::should_fail]
562    #[flux_rs::spec(fn bad_enqueue(self: &mut RingBuffer<T>, val: T) -> bool
563                        ensures self: RingBuffer<T>)]
564    fn bad_enqueue<T: Copy>(rb: &mut RingBuffer<T>, val: T) -> bool {
565        // This function will not panic as long as rb.tail < rb.ring.len().
566        // However, for this to be true, every RingBuffer method needs to
567        // maintain this invariant (which is encoded in our RingBuffer spec).
568        // This function does not maintain this invariant, as it increases
569        // tail without checking ring.len(), and will throw an error.
570        if rb.is_full() {
571            false
572        } else {
573            rb.ring[rb.tail].write(val);
574            // CORRECT: rb.tail = (rb.tail + 1) % rb.ring.len();
575            rb.tail = rb.tail + 1;
576            true
577        }
578    }
579}