From d362688fd9a86b9b3880e0f598d106627c50ab29 Mon Sep 17 00:00:00 2001 From: Josh Junon Date: Thu, 10 Oct 2024 13:26:22 +0200 Subject: [PATCH] sync: remove `oro-sync` in lieu of `spin` crate [no ci] --- Cargo.lock | 49 +++-- Cargo.toml | 3 +- oro-arch-aarch64/Cargo.toml | 3 +- oro-arch-aarch64/src/boot/mod.rs | 5 +- oro-arch-aarch64/src/init.rs | 4 +- oro-arch-aarch64/src/lib.rs | 4 +- oro-arch-aarch64/src/sync.rs | 28 --- oro-arch-x86_64/Cargo.toml | 3 +- oro-arch-x86_64/src/boot/mod.rs | 5 +- oro-arch-x86_64/src/init.rs | 21 +- oro-arch-x86_64/src/interrupt.rs | 7 +- oro-arch-x86_64/src/lib.rs | 2 - oro-arch-x86_64/src/sync.rs | 37 ---- oro-debug-pl011/Cargo.toml | 2 +- oro-debug-pl011/src/driver.rs | 3 + oro-debug-pl011/src/lib.rs | 15 +- oro-debug-uart16550/Cargo.toml | 2 +- oro-debug-uart16550/src/lib.rs | 12 +- oro-kernel/Cargo.toml | 3 +- oro-kernel/src/lib.rs | 88 +++----- oro-kernel/src/registry.rs | 61 +++--- oro-kernel/src/scheduler.rs | 10 +- oro-mem/Cargo.toml | 1 - oro-sync/Cargo.toml | 21 -- oro-sync/src/barrier.rs | 68 ------- oro-sync/src/lib.rs | 5 - oro-sync/src/spinlock/mod.rs | 6 - oro-sync/src/spinlock/unfair.rs | 116 ----------- oro-sync/src/spinlock/unfair_critical.rs | 246 ----------------------- 29 files changed, 135 insertions(+), 695 deletions(-) delete mode 100644 oro-arch-aarch64/src/sync.rs delete mode 100644 oro-arch-x86_64/src/sync.rs delete mode 100644 oro-sync/Cargo.toml delete mode 100644 oro-sync/src/barrier.rs delete mode 100644 oro-sync/src/lib.rs delete mode 100644 oro-sync/src/spinlock/mod.rs delete mode 100644 oro-sync/src/spinlock/unfair.rs delete mode 100644 oro-sync/src/spinlock/unfair_critical.rs diff --git a/Cargo.lock b/Cargo.lock index dace3507..5d333e6b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11,6 +11,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "autocfg" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" + [[package]] name = "bindgen" version = "0.70.1" @@ -129,6 +135,16 @@ dependencies = [ "bitflags 2.6.0", ] +[[package]] +name = "lock_api" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +dependencies = [ + "autocfg", + "scopeguard", +] + [[package]] name = "log" version = "0.4.22" @@ -189,8 +205,8 @@ dependencies = [ "oro-kernel", "oro-macro", "oro-mem", - "oro-sync", "oro-type", + "spin", ] [[package]] @@ -206,7 +222,7 @@ dependencies = [ "oro-kernel", "oro-macro", "oro-mem", - "oro-sync", + "spin", ] [[package]] @@ -262,7 +278,7 @@ dependencies = [ name = "oro-debug-pl011" version = "0.0.0" dependencies = [ - "oro-sync", + "spin", "volatile-register", ] @@ -270,7 +286,7 @@ dependencies = [ name = "oro-debug-uart16550" version = "0.0.0" dependencies = [ - "oro-sync", + "spin", "uart_16550", ] @@ -300,7 +316,7 @@ dependencies = [ "oro-id", "oro-macro", "oro-mem", - "oro-sync", + "spin", ] [[package]] @@ -328,14 +344,6 @@ dependencies = [ "oro-debug", "oro-elf", "oro-macro", - "oro-sync", -] - -[[package]] -name = "oro-sync" -version = "0.0.0" -dependencies = [ - "oro-dbgutil", ] [[package]] @@ -420,12 +428,27 @@ version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + [[package]] name = "shlex" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] + [[package]] name = "syn" version = "2.0.76" diff --git a/Cargo.toml b/Cargo.toml index f0168ee3..94f68571 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,7 +17,6 @@ members = [ "oro-bootloader-limine", "oro-mem", "oro-elf", - "oro-sync", "oro-macro", "oro-macro-proc", "oro-kernel", @@ -41,7 +40,6 @@ oro-mem.path = "oro-mem" oro-macro.path = "oro-macro" oro-macro-proc.path = "oro-macro-proc" oro-elf.path = "oro-elf" -oro-sync.path = "oro-sync" oro-kernel.path = "oro-kernel" oro-debug.path = "oro-debug" oro-debug-pl011.path = "oro-debug-pl011" @@ -54,6 +52,7 @@ oro-id.path = "oro-id" limine = "0.2.0" uart_16550 = "0.3.0" volatile-register = "0.2.2" +spin = { version = "0.9.8", features = ["ticket_mutex", "fair_mutex"] } bindgen = { git = "https://github.com/oro-os/dep.rust-bindgen.git" } syn = { version = "2.0.60", features = ["full", "printing"] } diff --git a/oro-arch-aarch64/Cargo.toml b/oro-arch-aarch64/Cargo.toml index 3277aa2b..7a7132c8 100644 --- a/oro-arch-aarch64/Cargo.toml +++ b/oro-arch-aarch64/Cargo.toml @@ -28,11 +28,12 @@ oro-boot-protocol.workspace = true oro-mem.workspace = true oro-macro.workspace = true oro-elf.workspace = true -oro-sync.workspace = true oro-debug.workspace = true oro-dtb.workspace = true oro-type.workspace = true oro-dbgutil.workspace = true +spin.workspace = true + [lints] workspace = true diff --git a/oro-arch-aarch64/src/boot/mod.rs b/oro-arch-aarch64/src/boot/mod.rs index 5bc21c63..7cbe8ce6 100644 --- a/oro-arch-aarch64/src/boot/mod.rs +++ b/oro-arch-aarch64/src/boot/mod.rs @@ -37,10 +37,7 @@ pub unsafe fn boot_primary() -> ! { crate::init::initialize_primary(pat.clone(), pfa); { - let mut pfa = crate::init::KERNEL_STATE - .assume_init_ref() - .pfa() - .lock::(); + let mut pfa = crate::init::KERNEL_STATE.assume_init_ref().pfa().lock(); // Boot secondaries. let num_cores = secondary::boot_secondaries(&mut *pfa, &pat, SECONDARY_STACK_PAGES); diff --git a/oro-arch-aarch64/src/init.rs b/oro-arch-aarch64/src/init.rs index 44036c85..482ef031 100644 --- a/oro-arch-aarch64/src/init.rs +++ b/oro-arch-aarch64/src/init.rs @@ -5,7 +5,7 @@ use core::mem::MaybeUninit; use oro_kernel::KernelState; use oro_mem::translate::OffsetTranslator; -use oro_sync::spinlock::unfair_critical::UnfairCriticalSpinlock; +use spin::mutex::fair::FairMutex; /// The global kernel state. Initialized once during boot /// and re-used across all cores. @@ -35,7 +35,7 @@ pub unsafe fn initialize_primary(pat: OffsetTranslator, pfa: crate::Pfa) { // SAFETY(qix-): We know what we're doing here. #[expect(static_mut_refs)] - KernelState::init(&mut KERNEL_STATE, pat, UnfairCriticalSpinlock::new(pfa)) + KernelState::init(&mut KERNEL_STATE, pat, FairMutex::new(pfa)) .expect("failed to create global kernel state"); } diff --git a/oro-arch-aarch64/src/lib.rs b/oro-arch-aarch64/src/lib.rs index f517f779..d28ed94d 100644 --- a/oro-arch-aarch64/src/lib.rs +++ b/oro-arch-aarch64/src/lib.rs @@ -37,7 +37,6 @@ pub mod mair; pub mod mem; pub mod psci; pub mod reg; -pub mod sync; pub(crate) mod init; @@ -63,13 +62,12 @@ pub(crate) struct Arch; impl oro_kernel::Arch for Arch { type AddrSpace = crate::mem::address_space::AddressSpaceLayout; - type IntCtrl = crate::sync::InterruptController; type Pat = OffsetTranslator; type Pfa = Pfa; } /// Type alias for the Oro kernel core-local instance type. -pub(crate) type Kernel = oro_kernel::Kernel; +pub(crate) type Kernel = oro_kernel::Kernel; /// Architecture-specific core-local state. pub(crate) struct CoreState { diff --git a/oro-arch-aarch64/src/sync.rs b/oro-arch-aarch64/src/sync.rs deleted file mode 100644 index 1c508067..00000000 --- a/oro-arch-aarch64/src/sync.rs +++ /dev/null @@ -1,28 +0,0 @@ -//! Provides synchronization-related types, traits and implementations. - -use core::arch::asm; - -/// Implements interupt controlling for unfair critical locks. -pub struct InterruptController; - -impl oro_sync::spinlock::unfair_critical::InterruptController for InterruptController { - type InterruptState = usize; - - fn disable_interrupts() { - crate::asm::disable_interrupts(); - } - - fn fetch_interrupts() -> Self::InterruptState { - let flags: usize; - unsafe { - asm!("mrs {}, daif", out(reg) flags, options(nostack, nomem)); - } - flags - } - - fn restore_interrupts(state: Self::InterruptState) { - unsafe { - asm!("msr daif, {}", in(reg) state, options(nostack, nomem)); - } - } -} diff --git a/oro-arch-x86_64/Cargo.toml b/oro-arch-x86_64/Cargo.toml index e0ccc0c3..7cec993f 100644 --- a/oro-arch-x86_64/Cargo.toml +++ b/oro-arch-x86_64/Cargo.toml @@ -28,11 +28,12 @@ oro-boot-protocol.workspace = true oro-mem.workspace = true oro-macro.workspace = true oro-elf.workspace = true -oro-sync.workspace = true oro-debug.workspace = true oro-dbgutil.workspace = true oro-acpi.workspace = true oro-id.workspace = true +spin.workspace = true + [lints] workspace = true diff --git a/oro-arch-x86_64/src/boot/mod.rs b/oro-arch-x86_64/src/boot/mod.rs index c0c60f00..08a4d218 100644 --- a/oro-arch-x86_64/src/boot/mod.rs +++ b/oro-arch-x86_64/src/boot/mod.rs @@ -117,10 +117,7 @@ pub unsafe fn boot_primary() -> ! { crate::init::initialize_primary(pat.clone(), pfa); { - let mut pfa = crate::init::KERNEL_STATE - .assume_init_ref() - .pfa() - .lock::(); + let mut pfa = crate::init::KERNEL_STATE.assume_init_ref().pfa().lock(); let num_cores = if has_cs89 { dbg!("physical pages 0x8000/0x9000 are valid; attempting to boot secondary cores"); diff --git a/oro-arch-x86_64/src/init.rs b/oro-arch-x86_64/src/init.rs index a74d2f7c..d6423d2e 100644 --- a/oro-arch-x86_64/src/init.rs +++ b/oro-arch-x86_64/src/init.rs @@ -11,7 +11,7 @@ use oro_mem::{ pfa::alloc::Alloc, translate::{OffsetTranslator, Translator}, }; -use oro_sync::spinlock::unfair_critical::UnfairCriticalSpinlock; +use spin::mutex::fair::FairMutex; use crate::{ gdt::{Gdt, SysEntry}, @@ -53,12 +53,8 @@ pub unsafe fn initialize_primary(pat: OffsetTranslator, pfa: crate::Pfa) { // SAFETY(qix-): We know what we're doing here. #[expect(static_mut_refs)] - KernelState::init( - &mut KERNEL_STATE, - pat.clone(), - UnfairCriticalSpinlock::new(pfa), - ) - .expect("failed to create global kernel state"); + KernelState::init(&mut KERNEL_STATE, pat.clone(), FairMutex::new(pfa)) + .expect("failed to create global kernel state"); let state = KERNEL_STATE.assume_init_ref(); @@ -102,9 +98,7 @@ pub unsafe fn initialize_primary(pat: OffsetTranslator, pfa: crate::Pfa) { .expect("failed to create root ring module"); let entry_point = { - let module_lock = module_handle - .try_lock::() - .expect("failed to lock module"); + let module_lock = module_handle.try_lock().expect("failed to lock module"); let mapper = module_lock.mapper(); @@ -146,10 +140,7 @@ pub unsafe fn initialize_primary(pat: OffsetTranslator, pfa: crate::Pfa) { segment.target_size() ); - let mut pfa = state - .pfa() - .try_lock::() - .expect("failed to lock pfa"); + let mut pfa = state.pfa().try_lock().expect("failed to lock pfa"); // NOTE(qix-): This will almost definitely be improved in the future. // NOTE(qix-): At the very least, hugepages will change this. @@ -265,7 +256,7 @@ pub unsafe fn boot(lapic: Lapic) -> ! { if let Some(user_ctx) = maybe_ctx { let (thread_cr3_phys, thread_rsp, kernel_rsp, kernel_irq_rsp) = unsafe { - let ctx_lock = user_ctx.lock_noncritical(); + let ctx_lock = user_ctx.lock(); let cr3 = ctx_lock.mapper().base_phys; let rsp = ctx_lock.thread_state().irq_stack_ptr; let kernel_rsp_ptr = kernel.core().kernel_stack.get() as u64; diff --git a/oro-arch-x86_64/src/interrupt.rs b/oro-arch-x86_64/src/interrupt.rs index a125e15a..ae81eef1 100644 --- a/oro-arch-x86_64/src/interrupt.rs +++ b/oro-arch-x86_64/src/interrupt.rs @@ -98,10 +98,7 @@ unsafe extern "C" fn isr_sys_timer_rust() -> ! { // If this is `None`, then the kernel is currently running. // Otherwise it's a userspace task that we just jumped from. if let Some(user_task) = scheduler_lock.current_thread().as_ref() { - user_task - .lock_noncritical() - .thread_state_mut() - .irq_stack_ptr = irq_stack_ptr; + user_task.lock().thread_state_mut().irq_stack_ptr = irq_stack_ptr; coming_from_user = true; } else { @@ -126,7 +123,7 @@ unsafe extern "C" fn isr_sys_timer_rust() -> ! { if let Some(user_ctx) = maybe_user_context { let (thread_cr3_phys, thread_rsp) = unsafe { - let ctx_lock = user_ctx.lock_noncritical(); + let ctx_lock = user_ctx.lock(); let cr3 = ctx_lock.mapper().base_phys; let rsp = ctx_lock.thread_state().irq_stack_ptr; (*handler.kernel().core().tss.get()) diff --git a/oro-arch-x86_64/src/lib.rs b/oro-arch-x86_64/src/lib.rs index b66e06ec..2e3e6626 100644 --- a/oro-arch-x86_64/src/lib.rs +++ b/oro-arch-x86_64/src/lib.rs @@ -77,7 +77,6 @@ pub mod interrupt; pub mod lapic; pub mod mem; pub mod reg; -pub mod sync; pub mod task; pub mod tss; @@ -111,7 +110,6 @@ pub(crate) struct Arch; impl oro_kernel::Arch for Arch { type AddrSpace = crate::mem::address_space::AddressSpaceLayout; type CoreState = CoreState; - type IntCtrl = crate::sync::InterruptController; type Pat = OffsetTranslator; type Pfa = Pfa; type ThreadState = ThreadState; diff --git a/oro-arch-x86_64/src/sync.rs b/oro-arch-x86_64/src/sync.rs deleted file mode 100644 index c62518a6..00000000 --- a/oro-arch-x86_64/src/sync.rs +++ /dev/null @@ -1,37 +0,0 @@ -//! Provides synchronization-related types, traits and implementations. - -use core::arch::asm; - -/// Implements interrupt controlling for unfair critical locks. -pub struct InterruptController; - -impl oro_sync::spinlock::unfair_critical::InterruptController for InterruptController { - type InterruptState = usize; - - fn disable_interrupts() { - crate::asm::disable_interrupts(); - } - - fn fetch_interrupts() -> Self::InterruptState { - let flags: usize; - unsafe { - asm!("pushfq", "pop {}", out(reg) flags, options(nostack)); - } - flags - } - - fn restore_interrupts(state: Self::InterruptState) { - unsafe { - asm!("push {}", "popfq", in(reg) state, options(nostack)); - } - } - - #[cfg(debug_assertions)] - fn interrupts_enabled() -> bool { - let eflags: usize; - unsafe { - asm!("pushfq", "pop {}", out(reg) eflags, options(nostack)); - } - (eflags & 0x200) != 0 - } -} diff --git a/oro-debug-pl011/Cargo.toml b/oro-debug-pl011/Cargo.toml index a0298724..af311252 100644 --- a/oro-debug-pl011/Cargo.toml +++ b/oro-debug-pl011/Cargo.toml @@ -12,8 +12,8 @@ repository = "https://github.com/oro-os/kernel" license = "MPL-2.0" [dependencies] -oro-sync.workspace = true volatile-register.workspace = true +spin.workspace = true [lints] workspace = true diff --git a/oro-debug-pl011/src/driver.rs b/oro-debug-pl011/src/driver.rs index 3a8fccbb..6637582d 100644 --- a/oro-debug-pl011/src/driver.rs +++ b/oro-debug-pl011/src/driver.rs @@ -21,6 +21,9 @@ pub struct PL011 { parity: Parity, } +// SAFETY(qix-): We know that the register block is safe to share. +unsafe impl Send for PL011 {} + /// Specifies the parity bit settings for the UART. #[derive(Clone, Copy, Debug, PartialEq, Eq)] #[repr(u8)] diff --git a/oro-debug-pl011/src/lib.rs b/oro-debug-pl011/src/lib.rs index 1f3512ac..6154a143 100644 --- a/oro-debug-pl011/src/lib.rs +++ b/oro-debug-pl011/src/lib.rs @@ -10,12 +10,12 @@ mod driver; use core::fmt::{self, Write}; -use oro_sync::spinlock::unfair::UnfairSpinlock; +use spin::mutex::fair::FairMutex; /// The shared serial port for the system. // NOTE(qix-): This is a temporary solution until pre-boot module loading // NOTE(qix-): is implemented. -static SERIAL: UnfairSpinlock> = UnfairSpinlock::new(None); +static SERIAL: FairMutex> = FairMutex::new(None); /// Initializes the PL011. pub fn init(offset: usize) { @@ -39,13 +39,10 @@ pub fn init(offset: usize) { /// Logs a message to the PL011. #[expect(clippy::missing_panics_doc)] pub fn log(message: fmt::Arguments) { - // NOTE(qix-): This unsafe block MUST NOT PANIC. - unsafe { - if let Some(serial) = SERIAL.lock().as_mut() { - writeln!(serial, "{message}") - } else { - Ok(()) - } + if let Some(serial) = SERIAL.lock().as_mut() { + writeln!(serial, "{message}") + } else { + Ok(()) } .unwrap(); } diff --git a/oro-debug-uart16550/Cargo.toml b/oro-debug-uart16550/Cargo.toml index e8bec696..efa9cdc2 100644 --- a/oro-debug-uart16550/Cargo.toml +++ b/oro-debug-uart16550/Cargo.toml @@ -12,8 +12,8 @@ repository = "https://github.com/oro-os/kernel" license = "MPL-2.0" [dependencies] -oro-sync.workspace = true uart_16550.workspace = true +spin.workspace = true [lints] workspace = true diff --git a/oro-debug-uart16550/src/lib.rs b/oro-debug-uart16550/src/lib.rs index a930132f..dfbf4286 100644 --- a/oro-debug-uart16550/src/lib.rs +++ b/oro-debug-uart16550/src/lib.rs @@ -4,23 +4,19 @@ use core::fmt::{self, Write}; -use oro_sync::spinlock::unfair::UnfairSpinlock; +use spin::mutex::fair::FairMutex; use uart_16550::SerialPort; /// The shared serial port for the system. -static SERIAL: UnfairSpinlock = UnfairSpinlock::new(unsafe { SerialPort::new(0x3F8) }); +static SERIAL: FairMutex = FairMutex::new(unsafe { SerialPort::new(0x3F8) }); /// Initializes the UART. pub fn init() { - // SAFETY(qix-): This is safe, even if we call it multiple times. - unsafe { - SERIAL.lock().init(); - } + SERIAL.lock().init(); } /// Logs a message to the UART. #[expect(clippy::missing_panics_doc)] pub fn log(message: fmt::Arguments) { - // NOTE(qix-): This unsafe block MUST NOT PANIC. - unsafe { writeln!(SERIAL.lock(), "{message}") }.unwrap(); + writeln!(SERIAL.lock(), "{message}").unwrap(); } diff --git a/oro-kernel/Cargo.toml b/oro-kernel/Cargo.toml index 0cbe7c0c..cb383e2d 100644 --- a/oro-kernel/Cargo.toml +++ b/oro-kernel/Cargo.toml @@ -14,9 +14,10 @@ license = "MPL-2.0" [dependencies] oro-mem.workspace = true oro-macro.workspace = true -oro-sync.workspace = true oro-id.workspace = true oro-debug.workspace = true +spin.workspace = true + [lints] workspace = true diff --git a/oro-kernel/src/lib.rs b/oro-kernel/src/lib.rs index c5bee239..a0e50bbe 100644 --- a/oro-kernel/src/lib.rs +++ b/oro-kernel/src/lib.rs @@ -30,10 +30,7 @@ use oro_mem::{ pfa::alloc::Alloc, translate::Translator, }; -use oro_sync::spinlock::{ - unfair::UnfairSpinlock, - unfair_critical::{InterruptController, UnfairCriticalSpinlock}, -}; +use spin::mutex::fair::FairMutex; use self::{ registry::{Handle, List, ListRegistry, Registry}, @@ -58,7 +55,7 @@ pub struct Kernel { /// The kernel scheduler. /// /// Guaranteed valid after a successful call to `initialize_for_core`. - scheduler: MaybeUninit>>, + scheduler: MaybeUninit>>, /// Cached mapper handle for the kernel. mapper: SupervisorHandle, } @@ -97,7 +94,7 @@ impl Kernel { debug_assert!((kernel_base as *mut Self).is_aligned()); { - let mut pfa = global_state.pfa.lock::(); + let mut pfa = global_state.pfa.lock(); let phys = pfa.allocate().ok_or(MapError::OutOfMemory)?; core_local_segment.map(&mapper, &mut *pfa, &global_state.pat, kernel_base, phys)?; } @@ -113,7 +110,7 @@ impl Kernel { (*kernel_ptr) .scheduler - .write(UnfairSpinlock::new(Scheduler::new(&*kernel_ptr))); + .write(FairMutex::new(Scheduler::new(&*kernel_ptr))); Ok(&*kernel_ptr) } @@ -167,9 +164,7 @@ impl Kernel { /// interrupts are disabled; the spinlock is _not_ a critical /// spinlock and thus does not disable interrupts. #[must_use] - pub unsafe fn scheduler(&self) -> &UnfairSpinlock> { - #[cfg(debug_assertions)] - debug_assert!(!A::IntCtrl::interrupts_enabled()); + pub unsafe fn scheduler(&self) -> &FairMutex> { self.scheduler.assume_init_ref() } } @@ -179,7 +174,7 @@ impl Kernel { pub struct KernelState { /// The shared, spinlocked page frame allocator (PFA) for the /// entire system. - pfa: UnfairCriticalSpinlock, + pfa: FairMutex, /// The physical address translator. pat: A::Pat, @@ -259,14 +254,14 @@ impl KernelState { pub unsafe fn init( this: &'static mut MaybeUninit, pat: A::Pat, - pfa: UnfairCriticalSpinlock, + pfa: FairMutex, ) -> Result<(), MapError> { #[expect(clippy::missing_docs_in_private_items)] macro_rules! init_registries { ($($id:ident => $(($listregfn:ident, $itemregfn:ident))? $($regfn:ident)?),* $(,)?) => { $( let $id = { - let mut pfa_lock = pfa.lock::(); + let mut pfa_lock = pfa.lock(); let reg = init_registries!(@inner pfa_lock, $(($listregfn, $itemregfn))? $($regfn)?); let _ = pfa_lock; @@ -307,9 +302,8 @@ impl KernelState { } let supervisor_space = AddrSpace::::current_supervisor_space(&pat); - let user_mapper = - AddrSpace::::new_user_space(&supervisor_space, &mut *pfa.lock::(), &pat) - .ok_or(MapError::OutOfMemory)?; + let user_mapper = AddrSpace::::new_user_space(&supervisor_space, &mut *pfa.lock(), &pat) + .ok_or(MapError::OutOfMemory)?; this.write(Self { pfa, @@ -361,7 +355,7 @@ impl KernelState { } /// Returns the underlying PFA belonging to the kernel state. - pub fn pfa(&'static self) -> &'static UnfairCriticalSpinlock { + pub fn pfa(&'static self) -> &'static FairMutex { &self.pfa } @@ -399,9 +393,8 @@ impl KernelState { }, )?; - // SAFETY(qix-): Will not panic. - unsafe { - ring.lock::().id = ring.id(); + { + ring.lock().id = ring.id(); } // SAFETY(qix-): As long as the kernel state has been initialized, @@ -420,8 +413,7 @@ impl KernelState { let instance_list = self.instance_list_registry.create_list(&self.pfa)?; let mapper = { - // SAFETY(qix-): We don't panic here. - let mut pfa = unsafe { self.pfa.lock::() }; + let mut pfa = self.pfa.lock(); AddrSpace::::duplicate_user_space_shallow(&self.user_mapper, &mut *pfa, &self.pat) .ok_or(MapError::OutOfMemory)? }; @@ -436,9 +428,8 @@ impl KernelState { }, )?; - // SAFETY(qix-): Will not panic. - unsafe { - module.lock::().id = module.id(); + { + module.lock().id = module.id(); } // SAFETY(qix-): As long as the kernel state has been initialized, @@ -462,10 +453,9 @@ impl KernelState { let thread_list = self.thread_list_registry.create_list(&self.pfa)?; let port_list = self.port_list_registry.create_list(&self.pfa)?; - // SAFETY(qix-): We don't panic here. - let mapper = unsafe { - let module_lock = module.lock::(); - let mut pfa = self.pfa.lock::(); + let mapper = { + let module_lock = module.lock(); + let mut pfa = self.pfa.lock(); AddrSpace::::duplicate_user_space_shallow(module_lock.mapper(), &mut *pfa, &self.pat) .ok_or(MapError::OutOfMemory)? }; @@ -482,20 +472,13 @@ impl KernelState { }, )?; - // SAFETY(qix-): Will not panic. - unsafe { - instance.lock::().id = instance.id(); + { + instance.lock().id = instance.id(); // SAFETY(qix-): As long as the kernel state has been initialized, // SAFETY(qix-): this won't panic. - let _ = module - .lock::() - .instances - .append(&self.pfa, instance.clone()); - let _ = ring - .lock::() - .instances - .append(&self.pfa, instance.clone()); + let _ = module.lock().instances.append(&self.pfa, instance.clone()); + let _ = ring.lock().instances.append(&self.pfa, instance.clone()); } Ok(instance) @@ -511,10 +494,9 @@ impl KernelState { stack_size: usize, mut thread_state: A::ThreadState, ) -> Result>, MapError> { - // SAFETY(qix-): We don't panic here. - let mapper = unsafe { - let instance_lock = instance.lock::(); - let mut pfa = self.pfa.lock::(); + let mapper = { + let instance_lock = instance.lock(); + let mut pfa = self.pfa.lock(); AddrSpace::::duplicate_user_space_shallow( instance_lock.mapper(), &mut *pfa, @@ -536,7 +518,7 @@ impl KernelState { let stack_low_guard = stack_first_page - 0x1000; let map_result = { - let mut pfa = self.pfa.lock::(); + let mut pfa = self.pfa.lock(); for virt in (stack_first_page..stack_high_guard).step_by(0x1000) { let phys = pfa.allocate().ok_or(MapError::OutOfMemory)?; @@ -594,12 +576,9 @@ impl KernelState { }, )?; - thread.lock::().id = thread.id(); + thread.lock().id = thread.id(); - let _ = instance - .lock::() - .threads - .append(&self.pfa, thread.clone())?; + let _ = instance.lock().threads.append(&self.pfa, thread.clone())?; let _ = self .threads @@ -613,7 +592,7 @@ impl KernelState { // Try to reclaim the memory we just allocated, if any. match map_result { Err(err) => { - let mut pfa = self.pfa.lock::(); + let mut pfa = self.pfa.lock(); if let Err(err) = A::reclaim_thread_mappings(&mapper, &mut thread_state, &mut *pfa, &self.pat) @@ -638,9 +617,8 @@ impl KernelState { } }; - // SAFETY(qix-): We don't panic here. - unsafe { - let mut thread_lock = thread.lock::(); + { + let mut thread_lock = thread.lock(); thread_lock.mapper.write(mapper); thread_lock.thread_state.write(thread_state); } @@ -658,8 +636,6 @@ pub trait Arch: 'static { /// The type of page frame allocator (PFA) the architecture /// uses. type Pfa: Alloc; - /// The type of interrupt controller. - type IntCtrl: InterruptController; /// The address space layout the architecture uses. type AddrSpace: AddressSpace; /// Architecture-specific thread state to be stored alongside diff --git a/oro-kernel/src/registry.rs b/oro-kernel/src/registry.rs index 3cd78785..1698bd42 100644 --- a/oro-kernel/src/registry.rs +++ b/oro-kernel/src/registry.rs @@ -32,7 +32,7 @@ use oro_mem::{ mapper::{AddressSegment, AddressSpace, MapError}, pfa::alloc::Alloc, }; -use oro_sync::spinlock::unfair_critical::UnfairCriticalSpinlock; +use spin::mutex::fair::FairMutex; use crate::{AddrSpace, Arch, SupervisorHandle, SupervisorSegment}; @@ -52,7 +52,7 @@ pub(crate) struct Registry { // TODO(qix-): a few bytes. base: *mut MaybeUninit>, /// Bookkeeping counters used in the registry. - bookkeeping: UnfairCriticalSpinlock, + bookkeeping: FairMutex, /// The segment this registry is in. segment: SupervisorSegment, /// The mapper for the registry. @@ -64,7 +64,7 @@ pub(crate) struct Registry { } /// Registry-level bookkeeping fields, protected -/// behind an [`UnfairCriticalSpinlock`]. +/// behind a [`FairMutex`]. struct RegistryBookkeeping { /// The last free ID in the registry. /// @@ -104,7 +104,7 @@ struct ItemFrame { /// next free slot. union MaybeItem { /// The item itself. - item: ManuallyDrop>, + item: ManuallyDrop>, /// The next free index. next_free: usize, } @@ -139,7 +139,7 @@ impl Registry { Ok(Self { base: segment.range().0 as *mut _, - bookkeeping: UnfairCriticalSpinlock::new(RegistryBookkeeping::new()), + bookkeeping: FairMutex::new(RegistryBookkeeping::new()), pat, segment, mapper, @@ -155,13 +155,12 @@ impl Registry { /// locking the PFA. pub fn insert( &'static self, - pfa: &UnfairCriticalSpinlock, + pfa: &FairMutex, item: impl Into, ) -> Result, MapError> { let item = item.into(); - // SAFETY(qix-): We don't panic in this function. - let mut bk = unsafe { self.bookkeeping.lock::() }; + let mut bk = self.bookkeeping.lock(); let id = if bk.last_free_id == usize::MAX { let byte_offset = bk.total_count * size_of::>>(); @@ -176,8 +175,7 @@ impl Registry { let new_page_count = new_page_end + 1; if new_page_count > bk.total_page_count { - // SAFETY(qix-): We don't panic in this function. - let mut pfa = unsafe { pfa.lock::() }; + let mut pfa = pfa.lock(); for page_id in bk.total_page_count..new_page_count { let page = pfa.allocate().ok_or(MapError::OutOfMemory)?; @@ -207,7 +205,7 @@ impl Registry { let slot = unsafe { &mut *self.base.add(id) }; slot.write(ItemFrame { maybe_item: MaybeItem { - item: ManuallyDrop::new(UnfairCriticalSpinlock::new(item)), + item: ManuallyDrop::new(FairMutex::new(item)), }, user_count: AtomicUsize::new(1), }); @@ -219,7 +217,7 @@ impl Registry { bk.last_free_id = unsafe { slot.maybe_item.next_free }; let last_user_count = slot.user_count.fetch_add(1, Ordering::Relaxed); debug_assert_eq!(last_user_count, 0); - slot.maybe_item.item = ManuallyDrop::new(UnfairCriticalSpinlock::new(item)); + slot.maybe_item.item = ManuallyDrop::new(FairMutex::new(item)); id }; @@ -250,7 +248,7 @@ impl Registry { // NOTE(qix-): We could load and then do a compare-and-swap, but this function // NOTE(qix-): really should be seldom used, and I'm not interested in // NOTE(qix-): fleshing it out further at this time. PR welcome. - let bk = self.bookkeeping.lock::(); + let bk = self.bookkeeping.lock(); if id >= bk.total_count { return None; @@ -278,7 +276,7 @@ trait RegistryAccess { /// This function performs no bounds checks, /// and assumes if an ID is passed in, it is /// valid. - unsafe fn get(&self, id: usize) -> &UnfairCriticalSpinlock; + unsafe fn get(&self, id: usize) -> &FairMutex; /// Increments the user count of the item at the given ID. /// @@ -309,7 +307,7 @@ trait RegistryAccess { } impl RegistryAccess for Registry { - unsafe fn get(&self, id: usize) -> &UnfairCriticalSpinlock { + unsafe fn get(&self, id: usize) -> &FairMutex { &(*self.base.add(id)).assume_init_ref().maybe_item.item } @@ -340,7 +338,7 @@ impl RegistryAccess for Registry { // SAFETY(qix-): DO NOT PUT THIS LOCK BEFORE THE ABOVE DROP. // SAFETY(qix-): YOU WILL DEADLOCK THE KERNEL. - let mut bk = self.bookkeeping.lock::(); + let mut bk = self.bookkeeping.lock(); slot.maybe_item.next_free = bk.last_free_id; bk.last_free_id = id; } @@ -350,7 +348,7 @@ impl RegistryAccess for Registry { /// A lightweight handle to an item in a registry. /// /// The handle is a reference-counted item in the registry, -/// and is a thin wrapper around an [`UnfairCriticalSpinlock`] +/// and is a thin wrapper around an [`FairMutex`] /// to the item itself. /// /// Handles can be safely `clone()`d. When the last handle @@ -388,7 +386,7 @@ impl Handle { } impl Deref for Handle { - type Target = UnfairCriticalSpinlock; + type Target = FairMutex; fn deref(&self) -> &Self::Target { // SAFETY(qix-): We can assume that, given this handle @@ -538,7 +536,7 @@ impl Item { } impl Deref for Item { - type Target = UnfairCriticalSpinlock; + type Target = FairMutex; fn deref(&self) -> &Self::Target { &self.handle @@ -551,19 +549,16 @@ impl Handle> { /// Note that the underlying handle is still kept, including /// any handles to the list item directly (i.e. `Self`). pub fn delete(&self) { - // SAFETY(qix-): We don't panic here. - let mut lock = unsafe { self.lock::() }; + let mut lock = self.lock(); if let Some(list) = lock.list.take() { - // SAFETY(qix-): We don't panic here. - let mut list_lock = unsafe { list.lock::() }; + let mut list_lock = list.lock(); debug_assert!(list_lock.count > 0); list_lock.count -= 1; match (lock.prev.take(), lock.next.take()) { // Middle of the list. (Some(prev), Some(next)) => { - // SAFETY(qix-): We don't panic here. - let mut prev_lock = unsafe { prev.lock::() }; - let mut next_lock = unsafe { next.lock::() }; + let mut prev_lock = prev.lock(); + let mut next_lock = next.lock(); debug_assert_eq!(prev_lock.next.as_ref(), Some(self)); debug_assert_eq!(next_lock.prev.as_ref(), Some(self)); @@ -573,7 +568,7 @@ impl Handle> { } // End of the list. (Some(prev), None) => { - let mut prev_lock = unsafe { prev.lock::() }; + let mut prev_lock = prev.lock(); debug_assert_eq!(prev_lock.next.as_ref(), Some(self)); debug_assert_eq!(list_lock.last.as_ref(), Some(self)); @@ -583,7 +578,7 @@ impl Handle> { } // Beginning of the list. (None, Some(next)) => { - let mut next_lock = unsafe { next.lock::() }; + let mut next_lock = next.lock(); debug_assert_eq!(next_lock.prev.as_ref(), Some(self)); debug_assert_eq!(list_lock.first.as_ref(), Some(self)); @@ -623,19 +618,17 @@ impl Handle> { /// Inserts an item to the end of the list. pub fn append( &self, - pfa: &UnfairCriticalSpinlock, + pfa: &FairMutex, item: Handle, ) -> Result>, MapError> { - // SAFETY(qix-): We don't panic here. - let mut list_lock = unsafe { self.lock::() }; + let mut list_lock = self.lock(); let item = list_lock.item_registry.insert(pfa, Item::new(item))?; { let last = list_lock.last.replace(item.clone()); - // SAFETY(qix-): We don't panic here. - let mut item_lock = unsafe { item.lock::() }; + let mut item_lock = item.lock(); item_lock.list = Some(self.clone()); item_lock.prev = last; @@ -706,7 +699,7 @@ impl ListRegistry { /// The list is empty when created. pub fn create_list( &'static self, - pfa: &UnfairCriticalSpinlock, + pfa: &FairMutex, ) -> Result>, MapError> { self.list_registry .insert(pfa, List::new(&self.item_registry)) diff --git a/oro-kernel/src/scheduler.rs b/oro-kernel/src/scheduler.rs index e9beb933..2236eafa 100644 --- a/oro-kernel/src/scheduler.rs +++ b/oro-kernel/src/scheduler.rs @@ -87,7 +87,7 @@ impl Scheduler { pub unsafe fn current_thread(&self) -> Option>> { self.current_thread .as_ref() - .map(|item| item.lock_noncritical().handle().clone()) + .map(|item| item.lock().handle().clone()) } /// Selects a new thread to run. @@ -111,7 +111,7 @@ impl Scheduler { loop { let selected_thread_item = if let Some(current_thread) = self.current_thread.take() { let next_thread = { - let current_thread_lock = current_thread.lock_noncritical(); + let current_thread_lock = current_thread.lock(); let next = if current_thread_lock.in_list() { current_thread_lock.next() } else { @@ -128,13 +128,13 @@ impl Scheduler { // If we've reached the end of the list, force breaking back into the kernel. Some(next_thread?) } else { - self.kernel.state().threads().lock_noncritical().first() + self.kernel.state().threads().lock().first() }?; self.current_thread = Some(selected_thread_item.clone()); - let selected_thread_item_lock = selected_thread_item.lock_noncritical(); - let mut selected_thread_lock = selected_thread_item_lock.lock_noncritical(); + let selected_thread_item_lock = selected_thread_item.lock(); + let mut selected_thread_lock = selected_thread_item_lock.lock(); let this_kernel_id = self.kernel.id(); diff --git a/oro-mem/Cargo.toml b/oro-mem/Cargo.toml index e1ef659b..04eb4f12 100644 --- a/oro-mem/Cargo.toml +++ b/oro-mem/Cargo.toml @@ -17,7 +17,6 @@ doctest = false [dependencies] oro-macro.workspace = true oro-elf.workspace = true -oro-sync.workspace = true oro-debug.workspace = true oro-dbgutil.workspace = true diff --git a/oro-sync/Cargo.toml b/oro-sync/Cargo.toml deleted file mode 100644 index 536a0930..00000000 --- a/oro-sync/Cargo.toml +++ /dev/null @@ -1,21 +0,0 @@ -[package] -name = "oro-sync" -version.workspace = true -description = "Common synchronization primitives used throughout the kernel" -publish = false -edition = "2021" -authors = [ - "Josh Junon (https//github.com/qix-)" -] -homepage = "https://oro.sh" -repository = "https://github.com/oro-os/kernel" -license = "MPL-2.0" - -[lib] -doctest = false - -[dependencies] -oro-dbgutil.workspace = true - -[lints] -workspace = true diff --git a/oro-sync/src/barrier.rs b/oro-sync/src/barrier.rs deleted file mode 100644 index 45d4eb1d..00000000 --- a/oro-sync/src/barrier.rs +++ /dev/null @@ -1,68 +0,0 @@ -//! Barrier types, used to synchronize multiple cores in lockstep. - -#![expect(clippy::module_name_repetitions)] - -use core::sync::atomic::{AtomicU64, Ordering}; - -/// An atomic, spin-based barrier used to synchronize multiprocessor -/// operations. -/// -/// This barrier is a bit different than other barriers -/// because it has two phases; the first is to wait for a total number -/// (that should come from exactly one core), and the second is to -/// wait for all cores to reach the barrier. -/// -/// This barrier is single-use. -pub struct SpinBarrier { - /// The number of cores that must reach the barrier before it is cleared. - count: AtomicU64, - /// The total number of cores that must reach the barrier before it is cleared. - /// Zero indicates that a total has not been set. - total: AtomicU64, -} - -impl SpinBarrier { - /// Creates a new `SpinBarrier` that will synchronize `total` cores. - #[expect(clippy::new_without_default)] - #[must_use] - pub const fn new() -> Self { - Self { - count: AtomicU64::new(0), - total: AtomicU64::new(0), - } - } - - /// Sets the total of the barrier. This does not increment the count - /// nor does it block; the caller must also call `wait()`. - /// - /// # Safety - /// Consumers must ensure that this function is called exactly ONCE - /// from a SINGLE core. - pub unsafe fn set_total(&self, total: u64) { - self.total.store(total, Ordering::Release); - } - - /// Waits at the barrier until all cores have reached it. - pub fn wait(&self) { - let mut total; - loop { - total = self.total.load(Ordering::Acquire); - - if total > 0 { - break; - } - - ::core::hint::spin_loop(); - } - - let count = self.count.fetch_add(1, Ordering::Acquire) + 1; - - if count == total { - self.count.store(0, Ordering::Release); - } else { - while self.count.load(Ordering::Acquire) != 0 { - ::core::hint::spin_loop(); - } - } - } -} diff --git a/oro-sync/src/lib.rs b/oro-sync/src/lib.rs deleted file mode 100644 index 68b1f014..00000000 --- a/oro-sync/src/lib.rs +++ /dev/null @@ -1,5 +0,0 @@ -//! synchronization primitives used throughout the Oro kernel. -#![cfg_attr(not(test), no_std)] - -pub mod barrier; -pub mod spinlock; diff --git a/oro-sync/src/spinlock/mod.rs b/oro-sync/src/spinlock/mod.rs deleted file mode 100644 index 193441f3..00000000 --- a/oro-sync/src/spinlock/mod.rs +++ /dev/null @@ -1,6 +0,0 @@ -//! Spinlock implementations, used to provide mutual exclusion in the kernel -//! between multiple threads of execution that may access the same resource -//! concurrently. - -pub mod unfair; -pub mod unfair_critical; diff --git a/oro-sync/src/spinlock/unfair.rs b/oro-sync/src/spinlock/unfair.rs deleted file mode 100644 index 7d522d26..00000000 --- a/oro-sync/src/spinlock/unfair.rs +++ /dev/null @@ -1,116 +0,0 @@ -//! Provides the [`UnfairSpinlock`] type, a simple spinlock that does not -//! guarantee fairness and may result in starvation. - -#![expect(clippy::module_name_repetitions)] - -use core::{ - cell::UnsafeCell, - sync::atomic::{AtomicBool, Ordering}, -}; - -/// The unfair spinlock is a simple spinlock that does not guarantee -/// fairness and may result in starvation. It is used in the kernel for its -/// simplicity and low overhead. -/// -/// Note that this implementation does _not_ put the system into a critical section. -/// If that behavior is desired, consider using an -/// [`crate::spinlock::unfair_critical::UnfairCriticalSpinlock`] instead. -pub struct UnfairSpinlock { - /// The value protected by the lock. - value: UnsafeCell, - /// Whether the lock is currently owned. - owned: AtomicBool, -} - -unsafe impl Sync for UnfairSpinlock {} - -impl UnfairSpinlock { - /// Creates a new `UnfairSpinlock`. - #[inline] - pub const fn new(value: T) -> Self { - Self { - owned: AtomicBool::new(false), - value: UnsafeCell::new(value), - } - } - - /// Attempts to acquire the lock. - /// - /// If the lock is currently owned by another core, this method will return `None`. - /// - /// # Safety - /// This function is not reentrant. - #[inline] - #[must_use] - pub unsafe fn try_lock(&self) -> Option> { - self.owned - .compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed) - .ok() - .map(|_| { - #[cfg(debug_assertions)] - oro_dbgutil::__oro_dbgutil_lock_acquire(::core::ptr::from_ref(&self.value) as usize); - - UnfairSpinlockGuard { - lock: &self.owned, - value: self.value.get(), - } - }) - } - - /// Locks the spinlock, blocking until it is acquired. - /// - /// # Safety - /// This function is not reentrant. - #[inline] - #[must_use] - pub unsafe fn lock(&self) -> UnfairSpinlockGuard { - loop { - if let Some(guard) = self.try_lock() { - return guard; - } - } - } -} - -/// A lock held by an [`UnfairSpinlock`]. -pub struct UnfairSpinlockGuard<'a, T> { - /// A handle to the 'owned' flag in the spinlock. - pub(crate) lock: &'a AtomicBool, - /// A pointer to the value protected by the spinlock. - pub(crate) value: *mut T, -} - -impl Drop for UnfairSpinlockGuard<'_, T> { - #[inline] - fn drop(&mut self) { - self.lock.store(false, Ordering::Release); - #[cfg(debug_assertions)] - oro_dbgutil::__oro_dbgutil_lock_release(self.value as usize); - } -} - -impl Default for UnfairSpinlock -where - T: Default, -{ - #[inline] - fn default() -> Self { - Self::new(Default::default()) - } -} - -impl core::ops::Deref for UnfairSpinlockGuard<'_, T> { - type Target = T; - - #[inline] - fn deref(&self) -> &Self::Target { - unsafe { &*self.value } - } -} - -impl core::ops::DerefMut for UnfairSpinlockGuard<'_, T> { - #[inline] - fn deref_mut(&mut self) -> &mut Self::Target { - unsafe { &mut *self.value } - } -} diff --git a/oro-sync/src/spinlock/unfair_critical.rs b/oro-sync/src/spinlock/unfair_critical.rs deleted file mode 100644 index 9bd3da33..00000000 --- a/oro-sync/src/spinlock/unfair_critical.rs +++ /dev/null @@ -1,246 +0,0 @@ -//! Provides the [`UnfairCriticalSpinlock`] type, a simple spinlock that does not -//! guarantee fairness and may result in starvation, that also disables -//! interrupts for the lifetime of an acquired lock. - -#![expect(clippy::module_name_repetitions)] - -use core::{ - cell::UnsafeCell, - marker::PhantomData, - sync::atomic::{AtomicBool, Ordering}, -}; - -use super::unfair::UnfairSpinlockGuard; - -/// Allows for an architecture-specific means of disabling and re-enabling -/// interrupts. -pub trait InterruptController: 'static { - /// The interrupt state for the architecture. - type InterruptState: Copy; - - /// Disables interrupts. - fn disable_interrupts(); - - /// Restores interrupts to the given state. - fn restore_interrupts(state: Self::InterruptState); - - /// Fetches the current interrupt state. - fn fetch_interrupts() -> Self::InterruptState; - - /// Returns whether or not interrupts are currently enabled. - /// - /// This is a debug-only function; implementations must - /// add a `#[cfg(debug_assertions)]` attribute to the function. - /// This is done to prevent misuse and race conditions, and only - /// as precondition checks in debug builds. - #[cfg(debug_assertions)] - fn interrupts_enabled() -> bool; -} - -/// The unfair critical spinlock is a simple spinlock that does not guarantee -/// fairness and may result in starvation. It is used in the kernel for its -/// simplicity and low overhead. -/// -/// Note that this implementation **puts the system into a critical section** -/// when a lock is acquired, which is exited when the lock is dropped. -/// -/// Thus, its locking methods are marked `unsafe`, as the code that acquires -/// the lock **must not panic** while the lock is held. -#[repr(C)] -pub struct UnfairCriticalSpinlock { - /// The value protected by the lock. - value: UnsafeCell, - /// Whether the lock is currently owned. - owned: AtomicBool, -} - -unsafe impl Sync for UnfairCriticalSpinlock {} - -impl UnfairCriticalSpinlock { - /// Creates a new `UnfairCriticalSpinlock`. - #[inline] - pub const fn new(value: T) -> Self { - Self { - owned: AtomicBool::new(false), - value: UnsafeCell::new(value), - } - } - - /// Attempts to acquire the lock. - /// - /// If the lock is currently owned by another core, this method will return `None`. - /// - /// # Safety - /// This method is unsafe because the code that acquires the lock **must not panic** - /// while the lock is held. - /// - /// This function is not reentrant. - #[inline] - #[must_use] - pub unsafe fn try_lock( - &self, - ) -> Option> { - self.owned - .compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed) - .ok() - .map(|_| { - let interrupt_state = C::fetch_interrupts(); - C::disable_interrupts(); - - #[cfg(debug_assertions)] - oro_dbgutil::__oro_dbgutil_lock_acquire(self.value.get() as usize); - - UnfairCriticalSpinlockGuard { - lock: &self.owned, - value: self.value.get(), - interrupt_state, - _arch: PhantomData, - } - }) - } - - /// Locks the spinlock, blocking until it is acquired. - /// - /// # Safety - /// This method is unsafe because the code that acquires the lock **must not panic** - /// while the lock is held. - /// - /// This function is not reentrant. - #[inline] - #[must_use] - pub unsafe fn lock(&self) -> UnfairCriticalSpinlockGuard { - let interrupt_state = C::fetch_interrupts(); - C::disable_interrupts(); - - loop { - if let Some(guard) = self.try_lock_with_interrupt_state::(interrupt_state) { - return guard; - } - } - } - - /// Tries to lock the spinlock, returning `None` if the lock is already held. - /// - /// # Safety - /// This method is unsafe because the code that acquires the lock **must not panic**. - /// Further, interrupts should be properly fetched prior to disabling them. - /// - /// This function is not reentrant. - #[inline] - #[must_use] - unsafe fn try_lock_with_interrupt_state( - &self, - interrupt_state: C::InterruptState, - ) -> Option> { - self.owned - .compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed) - .ok() - .map(|_| { - #[cfg(debug_assertions)] - oro_dbgutil::__oro_dbgutil_lock_acquire(self.value.get() as usize); - - UnfairCriticalSpinlockGuard { - lock: &self.owned, - value: self.value.get(), - interrupt_state, - _arch: PhantomData, - } - }) - } - - /// Tries to lock the spinlock using a non-critical section. - /// - /// # Safety - /// This method is unsafe because the code that acquires the lock **must not panic**. - /// - /// Further, interrupts should be disabled before calling this function. - #[inline] - #[must_use] - pub unsafe fn try_lock_noncritical(&self) -> Option> { - self.owned - .compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed) - .ok() - .map(|_| { - #[cfg(debug_assertions)] - oro_dbgutil::__oro_dbgutil_lock_acquire(self.value.get() as usize); - - UnfairSpinlockGuard { - lock: &self.owned, - value: self.value.get(), - } - }) - } - - /// Locks the spinlock using a non-critical section. - /// - /// # Safety - /// This method is unsafe because the code that acquires the lock **must not panic**. - /// - /// Further, interrupts should be disabled before calling this function. - #[inline] - #[must_use] - pub unsafe fn lock_noncritical(&self) -> UnfairSpinlockGuard { - loop { - if let Some(guard) = self.try_lock_noncritical() { - return guard; - } - ::core::hint::spin_loop(); - } - } -} - -/// A lock held by an [`UnfairCriticalSpinlock`]. -pub struct UnfairCriticalSpinlockGuard<'a, C: InterruptController, T> { - /// The interrupt state before the lock was acquired. - interrupt_state: C::InterruptState, - /// A handle to the `owned` flag in the spinlock. - lock: &'a AtomicBool, - /// The value protected by the lock. - value: *mut T, - /// The architecture this spinlock guard is for. - /// Used to restore interrupts on drop. - _arch: PhantomData, -} - -impl Drop for UnfairCriticalSpinlockGuard<'_, C, T> { - #[inline] - fn drop(&mut self) { - // NOTE(qix-): Please do not re-order. It is important - // NOTE(qix-): that the interrupt state is restored after - // NOTE(qix-): the lock is released, as there may be - // NOTE(qix-): an interrupt that comes in between the - // NOTE(qix-): lock release and the interrupt state - // NOTE(qix-): restoration, causing starvation of other cores - // NOTE(qix-): for the duration of the interrupt handler. - self.lock.store(false, Ordering::Release); - #[cfg(debug_assertions)] - oro_dbgutil::__oro_dbgutil_lock_release(self.value as usize); - C::restore_interrupts(self.interrupt_state); - } -} - -impl Default for UnfairCriticalSpinlock -where - T: Default, -{ - #[inline] - fn default() -> Self { - Self::new(Default::default()) - } -} - -impl core::ops::Deref for UnfairCriticalSpinlockGuard<'_, C, T> { - type Target = T; - - #[inline] - fn deref(&self) -> &Self::Target { - unsafe { &*self.value } - } -} - -impl core::ops::DerefMut for UnfairCriticalSpinlockGuard<'_, C, T> { - #[inline] - fn deref_mut(&mut self) -> &mut Self::Target { - unsafe { &mut *self.value } - } -}