Skip to content

Commit

Permalink
userlib: Add SpinLock Implementation
Browse files Browse the repository at this point in the history
Add a simple SpinLock implementation to the user library to protect
access to global state. At some point this needs to be replaces with a
non-busy waiting locking implementation.

Signed-off-by: Joerg Roedel <[email protected]>
  • Loading branch information
joergroedel committed Dec 11, 2024
1 parent e3db7d3 commit a0b39e6
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 0 deletions.
3 changes: 3 additions & 0 deletions user/lib/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@

#![no_std]

pub mod locking;

use core::panic::PanicInfo;
pub use locking::*;
pub use syscall::*;

#[macro_export]
Expand Down
71 changes: 71 additions & 0 deletions user/lib/src/locking.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
// SPDX-License-Identifier: MIT
//
// Copyright (c) 2024 SUSE LLC
//
// Author: Joerg Roedel <[email protected]>

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<T> Drop for LockGuard<'_, T> {
fn drop(&mut self) {
self.holder.fetch_add(1, Ordering::Release);
}
}

impl<T> Deref for LockGuard<'_, T> {
type Target = T;
fn deref(&self) -> &T {
self.data
}
}

impl<T> DerefMut for LockGuard<'_, T> {
fn deref_mut(&mut self) -> &mut T {
self.data
}
}

#[derive(Debug)]
pub struct SpinLock<T> {
current: AtomicU64,
holder: AtomicU64,
data: UnsafeCell<T>,
}

// SAFETY: SpinLock guarantees mutually exclusive access to wrapped data.
unsafe impl<T> Sync for SpinLock<T> {}

impl<'a, T> SpinLock<T> {
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() },
}
}
}

0 comments on commit a0b39e6

Please sign in to comment.