Next Generation WASM Microkernel Operating System
wasm os rust microkernel
at main 95 lines 3.0 kB view raw
1// Copyright 2025 Jonas Kruckenberg 2// 3// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or 4// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or 5// http://opensource.org/licenses/MIT>, at your option. This file may not be 6// copied, modified, or distributed except according to those terms. 7 8use core::hint; 9 10/// An [exponential backoff] for spin loops. 11/// 12/// This is a helper struct for spinning in a busy loop, with an exponentially 13/// increasing number of spins up to a maximum value. 14/// 15/// [exponential backoff]: https://en.wikipedia.org/wiki/Exponential_backoff 16#[derive(Debug, Copy, Clone)] 17pub struct Backoff { 18 exp: u8, 19 max: u8, 20} 21 22// === impl Backoff === 23 24impl Backoff { 25 /// The default maximum exponent (2^8). 26 /// 27 /// This is the maximum exponent returned by [`Backoff::new()`] and 28 /// [`Backoff::default()`]. To override the maximum exponent, use 29 /// [`Backoff::with_max_exponent()`]. 30 pub const DEFAULT_MAX_EXPONENT: u8 = 8; 31 32 /// Returns a new exponential backoff with the maximum exponent set to 33 /// [`Self::DEFAULT_MAX_EXPONENT`]. 34 #[must_use] 35 pub const fn new() -> Self { 36 Self { 37 exp: 0, 38 max: Self::DEFAULT_MAX_EXPONENT, 39 } 40 } 41 42 /// Returns a new exponential backoff with the provided max exponent. 43 /// 44 /// # Panics 45 /// 46 /// Panics if the `max` exponent is larger than [`Self::DEFAULT_MAX_EXPONENT`]. 47 #[must_use] 48 pub fn with_max_exponent(max: u8) -> Self { 49 assert!(max <= Self::DEFAULT_MAX_EXPONENT); 50 Self { exp: 0, max } 51 } 52 53 /// Backs off in a spin loop. 54 /// 55 /// This should be used when an operation needs to be retried because 56 /// another thread or core made progress. Depending on the target 57 /// architecture, this will generally issue a sequence of `pause` 58 /// instructions. 59 /// 60 /// Each time this function is called, it will issue `2^exp` [spin loop 61 /// hints], where `exp` is the current exponent value (starting at 0). If 62 /// `exp` is less than the configured maximum exponent, the exponent is 63 /// incremented once the spin is complete. 64 /// 65 /// [spin loop hints]: hint::spin_loop 66 #[inline(always)] 67 pub fn spin(&mut self) { 68 // Issue 2^exp pause instructions. 69 let spins = 1_u32 << self.exp; 70 71 for _ in 0..spins { 72 // In tests, especially in loom tests, we need to yield the thread back to the runtime 73 // so it can make progress. See https://github.com/tokio-rs/loom/issues/162#issuecomment-665128979 74 #[cfg(loom)] 75 crate::loom::thread::yield_now(); 76 77 hint::spin_loop(); 78 } 79 80 if self.exp < self.max { 81 self.exp += 1; 82 } 83 } 84 85 #[inline(always)] 86 pub fn reset(&mut self) { 87 self.exp = 0; 88 } 89} 90 91impl Default for Backoff { 92 fn default() -> Self { 93 Self::new() 94 } 95}