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}