Next Generation WASM Microkernel Operating System
at trap_handler 75 lines 2.3 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::{ 9 cell::Cell, 10 sync::atomic::{AtomicUsize, Ordering}, 11}; 12use cpu_local::cpu_local; 13 14/// A reason for forcing an immediate abort on panic. 15#[derive(Debug)] 16pub enum MustAbort { 17 // AlwaysAbort, 18 PanicInHook, 19} 20 21// Panic count for the current thread and whether a panic hook is currently 22// being executed. 23cpu_local! { 24 static LOCAL_PANIC_COUNT: Cell<(usize, bool)> = Cell::new((0, false)); 25} 26 27static GLOBAL_PANIC_COUNT: AtomicUsize = AtomicUsize::new(0); 28 29pub fn increase(run_panic_hook: bool) -> Option<MustAbort> { 30 let (count, in_panic_hook) = LOCAL_PANIC_COUNT.get(); 31 if in_panic_hook { 32 return Some(MustAbort::PanicInHook); 33 } 34 LOCAL_PANIC_COUNT.set((count + 1, run_panic_hook)); 35 None 36} 37 38pub fn finished_panic_hook() { 39 let (count, _) = LOCAL_PANIC_COUNT.get(); 40 LOCAL_PANIC_COUNT.set((count, false)); 41} 42 43pub fn decrease() { 44 GLOBAL_PANIC_COUNT.fetch_sub(1, Ordering::Relaxed); 45 let (count, _) = LOCAL_PANIC_COUNT.get(); 46 LOCAL_PANIC_COUNT.set((count - 1, false)); 47} 48 49// Disregards ALWAYS_ABORT_FLAG 50#[must_use] 51#[inline] 52pub fn count_is_zero() -> bool { 53 if GLOBAL_PANIC_COUNT.load(Ordering::Relaxed) == 0 { 54 // Fast path: if `GLOBAL_PANIC_COUNT` is zero, all threads 55 // (including the current one) will have `LOCAL_PANIC_COUNT` 56 // equal to zero, so TLS access can be avoided. 57 // 58 // In terms of performance, a relaxed atomic load is similar to a normal 59 // aligned memory read (e.g., a mov instruction in x86), but with some 60 // compiler optimization restrictions. On the other hand, a TLS access 61 // might require calling a non-inlinable function (such as `__tls_get_addr` 62 // when using the GD TLS model). 63 true 64 } else { 65 is_zero_slow_path() 66 } 67} 68 69// Slow path is in a separate function to reduce the amount of code 70// inlined from `count_is_zero`. 71#[inline(never)] 72#[cold] 73fn is_zero_slow_path() -> bool { 74 LOCAL_PANIC_COUNT.get().0 == 0 75}