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