diff --git a/user/lib/src/lib.rs b/user/lib/src/lib.rs index 958f16e97..365831150 100644 --- a/user/lib/src/lib.rs +++ b/user/lib/src/lib.rs @@ -6,7 +6,10 @@ #![no_std] +pub mod locking; + use core::panic::PanicInfo; +pub use locking::*; pub use syscall::*; #[macro_export] diff --git a/user/lib/src/locking.rs b/user/lib/src/locking.rs new file mode 100644 index 000000000..62f0c54c0 --- /dev/null +++ b/user/lib/src/locking.rs @@ -0,0 +1,71 @@ +// SPDX-License-Identifier: MIT +// +// Copyright (c) 2024 SUSE LLC +// +// Author: Joerg Roedel + +use core::cell::UnsafeCell; +use core::ops::{Deref, DerefMut}; +use core::sync::atomic::{AtomicU64, Ordering}; + +#[derive(Debug)] +pub struct LockGuard<'a, T> { + holder: &'a AtomicU64, + data: &'a mut T, +} + +impl Drop for LockGuard<'_, T> { + fn drop(&mut self) { + self.holder.fetch_add(1, Ordering::Release); + } +} + +impl Deref for LockGuard<'_, T> { + type Target = T; + fn deref(&self) -> &T { + self.data + } +} + +impl DerefMut for LockGuard<'_, T> { + fn deref_mut(&mut self) -> &mut T { + self.data + } +} + +#[derive(Debug)] +pub struct SpinLock { + current: AtomicU64, + holder: AtomicU64, + data: UnsafeCell, +} + +// SAFETY: SpinLock guarantees mutually exclusive access to wrapped data. +unsafe impl Sync for SpinLock {} + +impl<'a, T> SpinLock { + pub const fn new(data: T) -> Self { + SpinLock { + current: AtomicU64::new(0), + holder: AtomicU64::new(0), + data: UnsafeCell::new(data), + } + } + + pub fn lock(&'a self) -> LockGuard<'a, T> { + let ticket = self.current.fetch_add(1, Ordering::Relaxed); + loop { + let h = self.holder.load(Ordering::Acquire); + if h == ticket { + break; + } + } + + LockGuard { + holder: &self.holder, + // SAFETY: Safe because at this point the lock is held and this is + // guaranteed to be the only reference. + data: unsafe { &mut *self.data.get() }, + } + } +}