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}