Explorar el Código

locked: move Locked to enoix_sync

greatbridf hace 10 meses
padre
commit
8384960da7

+ 4 - 0
crates/eonix_sync/Cargo.toml

@@ -5,3 +5,7 @@ edition = "2024"
 
 [dependencies]
 eonix_preempt = { path = "../eonix_preempt" }
+
+[features]
+default = []
+no_check_locked = []

+ 2 - 0
crates/eonix_sync/src/lib.rs

@@ -2,11 +2,13 @@
 
 mod guard;
 mod lock;
+mod locked;
 mod spin;
 mod strategy;
 
 pub use guard::Guard;
 pub use lock::Lock;
+pub use locked::{AsProof, AsProofMut, Locked, Proof, ProofMut};
 pub use spin::{IrqStrategy, SpinStrategy};
 pub use strategy::LockStrategy;
 

+ 95 - 0
crates/eonix_sync/src/locked.rs

@@ -0,0 +1,95 @@
+mod proof;
+
+use core::{cell::UnsafeCell, fmt, ptr::NonNull};
+
+pub use proof::{AsProof, AsProofMut, Proof, ProofMut};
+
+/// A lock to protect a value of type `T` using the proof of access to some
+/// value of type `U`.
+pub struct Locked<T, U>
+where
+    U: ?Sized,
+{
+    inner: UnsafeCell<T>,
+    #[cfg(not(feature = "no_check_locked"))]
+    guard: NonNull<U>,
+    #[cfg(feature = "no_check_locked")]
+    _phantom: core::marker::PhantomData<NonNull<U>>,
+}
+
+/// SAFETY: The `Locked` type is safe to send across threads as long as
+/// the inner type `T` is `Send`. The `guard` pointer is not used to access
+/// the inner value, so no constraints are needed on it.
+unsafe impl<T, U> Send for Locked<T, U>
+where
+    T: Send,
+    U: ?Sized,
+{
+}
+
+/// SAFETY: The `Locked` type is safe to share across threads as long as
+/// the inner type `T` is `Send` and `Sync`. The `guard` pointer is not used
+/// to access the inner value, so no constraints are needed on it.
+unsafe impl<T, U> Sync for Locked<T, U>
+where
+    T: Send + Sync,
+    U: ?Sized,
+{
+}
+
+impl<T, U> Locked<T, U>
+where
+    U: ?Sized,
+{
+    pub const fn new(value: T, guard: &U) -> Self {
+        Self {
+            inner: UnsafeCell::new(value),
+            #[cfg(not(feature = "no_check_locked"))]
+            // SAFETY: The validity of address is guaranteed by the borrow checker.
+            guard: unsafe { NonNull::new_unchecked(&raw const *guard as *mut U) },
+            #[cfg(feature = "no_check_locked")]
+            guard: core::marker::PhantomData,
+        }
+    }
+}
+
+impl<T, U> Locked<T, U>
+where
+    T: Send + Sync,
+    U: ?Sized,
+{
+    pub fn access<'a, 'b>(&'a self, _guard: Proof<'b, U>) -> &'a T
+    where
+        'b: 'a,
+    {
+        #[cfg(not(feature = "no_check_locked"))]
+        assert_eq!(self.guard, _guard.address, "Locked::access(): Wrong guard");
+        // SAFETY: The guard protects the shared access to the inner value.
+        unsafe { self.inner.get().as_ref().unwrap() }
+    }
+
+    pub fn access_mut<'a, 'b>(&'a self, _guard: ProofMut<'b, U>) -> &'a mut T
+    where
+        'b: 'a,
+    {
+        #[cfg(not(feature = "no_check_locked"))]
+        assert_eq!(
+            self.guard, _guard.address,
+            "Locked::access_mut(): Wrong guard"
+        );
+        // SAFETY: The guard protects the exclusive access to the inner value.
+        unsafe { self.inner.get().as_mut().unwrap() }
+    }
+}
+
+impl<T, U> fmt::Debug for Locked<T, U>
+where
+    U: ?Sized,
+{
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_struct("Locked")
+            .field("value", &self.inner)
+            .field("guard", &self.guard)
+            .finish()
+    }
+}

+ 192 - 0
crates/eonix_sync/src/locked/proof.rs

@@ -0,0 +1,192 @@
+use crate::{Guard, LockStrategy};
+use core::{marker::PhantomData, ptr::NonNull};
+
+/// A proof of mutable access to a position in memory with lifetime `'pos`.
+///
+/// Note that this is just the proof of access, we aren't actually permitted
+/// to mutate the memory location.
+///
+/// We can choose whether to check the validity of the proof or not at runtime.
+pub struct ProofMut<'pos, T>
+where
+    T: ?Sized,
+{
+    pub(super) address: NonNull<T>,
+    _phantom: PhantomData<&'pos ()>,
+}
+
+/// A proof of immutable access to a position in memory with lifetime `'pos`.
+///
+/// We can choose whether to check the validity of the proof or not at runtime.
+pub struct Proof<'pos, T>
+where
+    T: ?Sized,
+{
+    pub(super) address: NonNull<T>,
+    _phantom: PhantomData<&'pos ()>,
+}
+
+/// A trait for types that can be converted to a proof of mutable access.
+///
+/// This is used to prove that a mutable reference is valid for the lifetime `'pos`
+/// through this object with lifetime `'guard`.
+///
+/// ## Safety
+/// This trait is unsafe because it allows the caller to create a proof of access
+/// to a memory location that may not be valid for the lifetime `'pos`. The implementer
+/// must ensure that the access to the memory location is valid for the lifetime `'pos`
+/// during the lifetime of the returned `Proof`. This is typically done by using a lock
+/// or other synchronization mechanism to ensure that the memory location is not accessed
+/// by others while the proof is being created.
+pub unsafe trait AsProofMut<'guard, 'pos, T>: 'guard
+where
+    T: ?Sized,
+{
+    fn prove_mut(&self) -> ProofMut<'pos, T>
+    where
+        'guard: 'pos;
+}
+
+/// A trait for types that can be converted to a proof of immutable access.
+///
+/// This is used to prove that an immutable reference is valid for the lifetime `'pos`
+/// through this object with lifetime `'guard`.
+///
+/// ## Safety
+/// This trait is unsafe because it allows the caller to create a proof of access
+/// to a memory location that may not be valid for the lifetime `'pos`. The implementer
+/// must ensure that the access to the memory location is valid for the lifetime `'pos`
+/// during the lifetime of the returned `Proof`. This is typically done by using a lock
+/// or other synchronization mechanism to ensure that the memory location is not accessed
+/// by others while the proof is being created.
+pub unsafe trait AsProof<'guard, 'pos, T>: 'guard
+where
+    T: ?Sized,
+{
+    fn prove(&self) -> Proof<'pos, T>
+    where
+        'guard: 'pos;
+}
+
+/// Proof of mutable access to a position in memory can be duplicated.
+impl<T> Copy for ProofMut<'_, T> where T: ?Sized {}
+
+/// Proof of mutable access to a position in memory can be duplicated.
+impl<T> Clone for ProofMut<'_, T>
+where
+    T: ?Sized,
+{
+    fn clone(&self) -> Self {
+        Self {
+            address: self.address,
+            _phantom: self._phantom,
+        }
+    }
+}
+
+/// Proof of immutable access to a position in memory can be duplicated.
+impl<T> Copy for Proof<'_, T> where T: ?Sized {}
+
+/// Proof of immutable access to a position in memory can be duplicated.
+impl<T> Clone for Proof<'_, T>
+where
+    T: ?Sized,
+{
+    fn clone(&self) -> Self {
+        Self {
+            address: self.address,
+            _phantom: self._phantom,
+        }
+    }
+}
+
+/// SAFETY: The reference is valid for the lifetime `'guard`. So the access must be
+/// valid for the lifetime `'pos` that is shorter than `'guard`.
+unsafe impl<'guard, 'pos, T> AsProofMut<'guard, 'pos, T> for &'guard mut T
+where
+    T: ?Sized,
+{
+    fn prove_mut(&self) -> ProofMut<'pos, T>
+    where
+        'guard: 'pos,
+    {
+        ProofMut {
+            // SAFETY: The validity of the reference is guaranteed by the borrow checker.
+            address: unsafe { NonNull::new_unchecked(&raw const **self as *mut _) },
+            _phantom: PhantomData,
+        }
+    }
+}
+
+/// SAFETY: The lock is held for the lifetime `'guard`. So the access must be
+/// valid for the lifetime `'pos` that is shorter than `'guard`.
+unsafe impl<'lock, 'pos, T, S, L> AsProofMut<'lock, 'pos, T> for Guard<'lock, T, S, L, true>
+where
+    T: ?Sized,
+    S: LockStrategy + 'lock,
+    L: LockStrategy + 'lock,
+{
+    fn prove_mut(&self) -> ProofMut<'pos, T>
+    where
+        'lock: 'pos,
+    {
+        ProofMut {
+            address: unsafe { NonNull::new_unchecked(&raw const **self as *mut _) },
+            _phantom: PhantomData,
+        }
+    }
+}
+
+/// SAFETY: The reference is valid for the lifetime `'guard`. So the access must be
+/// valid for the lifetime `'pos` that is shorter than `'guard`.
+unsafe impl<'guard, 'pos, T> AsProof<'guard, 'pos, T> for &'guard T
+where
+    T: ?Sized,
+{
+    fn prove(&self) -> Proof<'pos, T>
+    where
+        'guard: 'pos,
+    {
+        Proof {
+            address: unsafe { NonNull::new_unchecked(&raw const **self as *mut _) },
+            _phantom: PhantomData,
+        }
+    }
+}
+
+/// SAFETY: The reference is valid for the lifetime `'guard`. So the access must be
+/// valid for the lifetime `'pos` that is shorter than `'guard`.
+unsafe impl<'guard, 'pos, T> AsProof<'guard, 'pos, T> for &'guard mut T
+where
+    T: ?Sized,
+{
+    fn prove(&self) -> Proof<'pos, T>
+    where
+        'guard: 'pos,
+    {
+        Proof {
+            address: unsafe { NonNull::new_unchecked(&raw const **self as *mut _) },
+            _phantom: PhantomData,
+        }
+    }
+}
+
+/// SAFETY: The lock is held for the lifetime `'guard`. So the access must be
+/// valid for the lifetime `'pos` that is shorter than `'guard`.
+unsafe impl<'lock, 'pos, T, S, L, const B: bool> AsProof<'lock, 'pos, T>
+    for Guard<'lock, T, S, L, B>
+where
+    T: ?Sized,
+    S: LockStrategy + 'lock,
+    L: LockStrategy + 'lock,
+{
+    fn prove(&self) -> Proof<'pos, T>
+    where
+        'lock: 'pos,
+    {
+        Proof {
+            address: unsafe { NonNull::new_unchecked(&raw const **self as *mut _) },
+            _phantom: PhantomData,
+        }
+    }
+}

+ 13 - 14
src/fs/procfs.rs

@@ -1,12 +1,3 @@
-use alloc::{
-    collections::btree_map::BTreeMap,
-    sync::{Arc, Weak},
-};
-use bindings::{EACCES, ENOTDIR};
-use core::{ops::ControlFlow, sync::atomic::Ordering};
-use itertools::Itertools;
-use lazy_static::lazy_static;
-
 use crate::{
     io::Buffer,
     kernel::{
@@ -21,8 +12,16 @@ use crate::{
         },
     },
     prelude::*,
-    sync::{AsRefMutPosition as _, AsRefPosition as _, Locked},
 };
+use alloc::{
+    collections::btree_map::BTreeMap,
+    sync::{Arc, Weak},
+};
+use bindings::{EACCES, ENOTDIR};
+use core::{ops::ControlFlow, sync::atomic::Ordering};
+use eonix_sync::{AsProof as _, AsProofMut as _, Locked};
+use itertools::Itertools;
+use lazy_static::lazy_static;
 
 fn split_len_offset(data: &[u8], len: usize, offset: usize) -> Option<&[u8]> {
     let real_data = data.split_at_checked(len).map(|(data, _)| data)?;
@@ -137,7 +136,7 @@ impl Inode for DirInode {
         let lock = self.rwsem.lock_shared();
         Ok(self
             .entries
-            .access(lock.as_pos())
+            .access(lock.prove())
             .iter()
             .find_map(|(name, node)| {
                 name.as_ref()
@@ -153,7 +152,7 @@ impl Inode for DirInode {
     ) -> KResult<usize> {
         let lock = self.rwsem.lock_shared();
         self.entries
-            .access(lock.as_pos())
+            .access(lock.prove())
             .iter()
             .skip(offset)
             .map(|(name, node)| callback(name.as_ref(), node.ino()))
@@ -242,7 +241,7 @@ pub fn creat(
         let lock = parent.idata.rwsem.lock();
         parent
             .entries
-            .access_mut(lock.as_pos_mut())
+            .access_mut(lock.prove_mut())
             .push((name, ProcFsNode::File(inode.clone())));
     }
 
@@ -263,7 +262,7 @@ pub fn mkdir(parent: &ProcFsNode, name: &[u8]) -> KResult<ProcFsNode> {
 
     parent
         .entries
-        .access_mut(inode.rwsem.lock().as_pos_mut())
+        .access_mut(inode.rwsem.lock().prove_mut())
         .push((Arc::from(name), ProcFsNode::Dir(inode.clone())));
 
     Ok(ProcFsNode::Dir(inode))

+ 15 - 16
src/fs/tmpfs.rs

@@ -1,8 +1,3 @@
-use alloc::sync::{Arc, Weak};
-use bindings::{EINVAL, EIO, EISDIR};
-use core::{ops::ControlFlow, sync::atomic::Ordering};
-use itertools::Itertools;
-
 use crate::{
     io::Buffer,
     kernel::constants::{S_IFBLK, S_IFCHR, S_IFDIR, S_IFLNK, S_IFREG},
@@ -15,8 +10,12 @@ use crate::{
         DevId,
     },
     prelude::*,
-    sync::{AsRefMutPosition as _, AsRefPosition as _, Locked, RefMutPosition},
 };
+use alloc::sync::{Arc, Weak};
+use bindings::{EINVAL, EIO, EISDIR};
+use core::{ops::ControlFlow, sync::atomic::Ordering};
+use eonix_sync::{AsProof as _, AsProofMut as _, Locked, ProofMut};
+use itertools::Itertools;
 
 fn acquire(vfs: &Weak<dyn Vfs>) -> KResult<Arc<dyn Vfs>> {
     vfs.upgrade().ok_or(EIO)
@@ -69,7 +68,7 @@ impl DirectoryInode {
         })
     }
 
-    fn link(&self, name: Arc<[u8]>, file: &dyn Inode, dlock: RefMutPosition<'_, ()>) {
+    fn link(&self, name: Arc<[u8]>, file: &dyn Inode, dlock: ProofMut<'_, ()>) {
         // SAFETY: Only `unlink` will do something based on `nlink` count
         //         No need to synchronize here
         file.nlink.fetch_add(1, Ordering::Relaxed);
@@ -89,7 +88,7 @@ impl Inode for DirectoryInode {
     ) -> KResult<usize> {
         let lock = self.rwsem.lock_shared();
         self.entries
-            .access(lock.as_pos())
+            .access(lock.prove())
             .iter()
             .skip(offset)
             .map(|(name, ino)| callback(&name, *ino))
@@ -107,7 +106,7 @@ impl Inode for DirectoryInode {
         let ino = vfs.assign_ino();
         let file = FileInode::new(ino, self.vfs.clone(), mode);
 
-        self.link(at.name().clone(), file.as_ref(), rwsem.as_pos_mut());
+        self.link(at.name().clone(), file.as_ref(), rwsem.prove_mut());
         at.save_reg(file)
     }
 
@@ -129,7 +128,7 @@ impl Inode for DirectoryInode {
             dev,
         );
 
-        self.link(at.name().clone(), file.as_ref(), rwsem.as_pos_mut());
+        self.link(at.name().clone(), file.as_ref(), rwsem.prove_mut());
         at.save_reg(file)
     }
 
@@ -142,7 +141,7 @@ impl Inode for DirectoryInode {
         let ino = vfs.assign_ino();
         let file = SymlinkInode::new(ino, self.vfs.clone(), target.into());
 
-        self.link(at.name().clone(), file.as_ref(), rwsem.as_pos_mut());
+        self.link(at.name().clone(), file.as_ref(), rwsem.prove_mut());
         at.save_symlink(file)
     }
 
@@ -155,7 +154,7 @@ impl Inode for DirectoryInode {
         let ino = vfs.assign_ino();
         let newdir = DirectoryInode::new(ino, self.vfs.clone(), mode);
 
-        self.link(at.name().clone(), newdir.as_ref(), rwsem.as_pos_mut());
+        self.link(at.name().clone(), newdir.as_ref(), rwsem.prove_mut());
         at.save_dir(newdir)
     }
 
@@ -172,7 +171,7 @@ impl Inode for DirectoryInode {
             return Err(EISDIR);
         }
 
-        let entries = self.entries.access_mut(dlock.as_pos_mut());
+        let entries = self.entries.access_mut(dlock.prove_mut());
         entries.retain(|(_, ino)| *ino != file.ino);
 
         assert_eq!(
@@ -268,7 +267,7 @@ impl Inode for FileInode {
         // TODO: We don't need that strong guarantee, find some way to avoid locks
         let lock = self.rwsem.lock_shared();
 
-        match self.filedata.access(lock.as_pos()).split_at_checked(offset) {
+        match self.filedata.access(lock.prove()).split_at_checked(offset) {
             Some((_, data)) => buffer.fill(data).map(|result| result.allow_partial()),
             None => Ok(0),
         }
@@ -277,7 +276,7 @@ impl Inode for FileInode {
     fn write(&self, buffer: &[u8], offset: WriteOffset) -> KResult<usize> {
         // TODO: We don't need that strong guarantee, find some way to avoid locks
         let lock = self.rwsem.lock();
-        let filedata = self.filedata.access_mut(lock.as_pos_mut());
+        let filedata = self.filedata.access_mut(lock.prove_mut());
 
         let offset = match offset {
             WriteOffset::Position(offset) => offset,
@@ -305,7 +304,7 @@ impl Inode for FileInode {
     fn truncate(&self, length: usize) -> KResult<()> {
         // TODO: We don't need that strong guarantee, find some way to avoid locks
         let lock = self.rwsem.lock();
-        let filedata = self.filedata.access_mut(lock.as_pos_mut());
+        let filedata = self.filedata.access_mut(lock.prove_mut());
 
         // SAFETY: `lock` has done the synchronization
         self.size.store(length as u64, Ordering::Relaxed);

+ 4 - 3
src/kernel/chardev.rs

@@ -9,12 +9,13 @@ use super::{
         DevId,
     },
 };
-use crate::{io::Buffer, prelude::*, sync::AsRefPosition as _};
+use crate::{io::Buffer, prelude::*};
 use alloc::{
     boxed::Box,
     collections::btree_map::{BTreeMap, Entry},
     sync::Arc,
 };
+use eonix_sync::AsProof as _;
 use lazy_static::lazy_static;
 
 pub trait VirtualCharDevice: Send + Sync {
@@ -77,11 +78,11 @@ impl CharDevice {
             CharDeviceType::Terminal(terminal) => {
                 let procs = ProcessList::get().lock_shared();
                 let current = Thread::current();
-                let session = current.process.session(procs.as_pos());
+                let session = current.process.session(procs.prove());
                 // We only set the control terminal if the process is the session leader.
                 if session.sid == Thread::current().process.pid {
                     // Silently fail if we can't set the control terminal.
-                    dont_check!(session.set_control_terminal(&terminal, false, procs.as_pos()));
+                    dont_check!(session.set_control_terminal(&terminal, false, procs.prove()));
                 }
 
                 TerminalFile::new(terminal.clone())

+ 9 - 9
src/kernel/syscall/procops.rs

@@ -15,7 +15,6 @@ use crate::kernel::user::{UserPointer, UserPointerMut};
 use crate::kernel::vfs::dentry::Dentry;
 use crate::kernel::vfs::{self, FsContext};
 use crate::path::Path;
-use crate::sync::AsRefPosition as _;
 use crate::{kernel::user::dataflow::UserBuffer, prelude::*};
 use alloc::borrow::ToOwned;
 use alloc::ffi::CString;
@@ -23,6 +22,7 @@ use arch::{ExtendedContext, InterruptContext};
 use bindings::{EINVAL, ENOENT, ENOTDIR, ERANGE, ESRCH};
 use bitflags::bitflags;
 use eonix_runtime::scheduler::Scheduler;
+use eonix_sync::AsProof as _;
 
 fn do_umask(mask: u32) -> KResult<u32> {
     let context = FsContext::get_current();
@@ -237,7 +237,7 @@ fn do_getsid(pid: u32) -> KResult<u32> {
         let procs = ProcessList::get().lock_shared();
         procs
             .try_find_process(pid)
-            .map(|proc| proc.session(procs.as_pos()).sid)
+            .map(|proc| proc.session(procs.prove()).sid)
             .ok_or(ESRCH)
     }
 }
@@ -249,7 +249,7 @@ fn do_getpgid(pid: u32) -> KResult<u32> {
         let procs = ProcessList::get().lock_shared();
         procs
             .try_find_process(pid)
-            .map(|proc| proc.pgroup(procs.as_pos()).pgid)
+            .map(|proc| proc.pgroup(procs.prove()).pgid)
             .ok_or(ESRCH)
     }
 }
@@ -332,18 +332,18 @@ fn do_kill(pid: i32, sig: u32) -> KResult<()> {
         // Send signal to every process in the process group.
         0 => Thread::current()
             .process
-            .pgroup(procs.as_pos())
-            .raise(Signal::try_from(sig)?, procs.as_pos()),
+            .pgroup(procs.prove())
+            .raise(Signal::try_from(sig)?, procs.prove()),
         // Send signal to the process with the specified pid.
         1.. => procs
             .try_find_process(pid as u32)
             .ok_or(ESRCH)?
-            .raise(Signal::try_from(sig)?, procs.as_pos()),
+            .raise(Signal::try_from(sig)?, procs.prove()),
         // Send signal to the process group with the specified pgid equals to `-pid`.
         ..-1 => procs
             .try_find_pgroup((-pid) as u32)
             .ok_or(ESRCH)?
-            .raise(Signal::try_from(sig)?, procs.as_pos()),
+            .raise(Signal::try_from(sig)?, procs.prove()),
     }
 
     Ok(())
@@ -586,8 +586,8 @@ fn sys_fork(int_stack: &mut InterruptContext, _: &mut ExtendedContext) -> usize
 
     let current = Thread::current();
     let current_process = current.process.clone();
-    let current_pgroup = current_process.pgroup(procs.as_pos()).clone();
-    let current_session = current_process.session(procs.as_pos()).clone();
+    let current_pgroup = current_process.pgroup(procs.prove()).clone();
+    let current_session = current_process.session(procs.prove()).clone();
 
     let mut new_int_context = int_stack.clone();
     new_int_context.set_return_value(0);

+ 19 - 24
src/kernel/task/process.rs

@@ -6,10 +6,7 @@ use crate::{
     kernel::mem::MMList,
     prelude::*,
     rcu::{rcu_sync, RCUPointer, RCUReadGuard},
-    sync::{
-        AsRefMutPosition as _, AsRefPosition as _, CondVar, RefMutPosition, RefPosition,
-        RwSemReadGuard, SpinGuard,
-    },
+    sync::{CondVar, RwSemReadGuard, SpinGuard},
 };
 use alloc::{
     collections::{btree_map::BTreeMap, vec_deque::VecDeque},
@@ -17,6 +14,7 @@ use alloc::{
 };
 use bindings::{ECHILD, EINTR, EPERM, ESRCH};
 use core::sync::atomic::{AtomicU32, Ordering};
+use eonix_sync::{AsProof as _, AsProofMut as _, Locked, Proof, ProofMut};
 use pointers::BorrowedArc;
 
 pub struct ProcessBuilder {
@@ -206,7 +204,7 @@ impl ProcessBuilder {
 
         let pgroup = match self.pgroup {
             Some(pgroup) => {
-                pgroup.add_member(&process, process_list.as_pos_mut());
+                pgroup.add_member(&process, process_list.prove_mut());
                 pgroup
             }
             None => ProcessGroupBuilder::new()
@@ -216,7 +214,7 @@ impl ProcessBuilder {
         };
 
         if let Some(parent) = &self.parent {
-            parent.add_child(&process, process_list.as_pos_mut());
+            parent.add_child(&process, process_list.prove_mut());
         }
 
         // SAFETY: We are holding the process list lock.
@@ -231,7 +229,7 @@ impl ProcessBuilder {
 }
 
 impl Process {
-    pub fn raise(&self, signal: Signal, procs: RefPosition<'_, ProcessList>) {
+    pub fn raise(&self, signal: Signal, procs: Proof<'_, ProcessList>) {
         let inner = self.inner.access(procs);
         for thread in inner.threads.values().map(|t| t.upgrade().unwrap()) {
             if let RaiseResult::Finished = thread.raise(signal) {
@@ -240,7 +238,7 @@ impl Process {
         }
     }
 
-    pub(super) fn add_child(&self, child: &Arc<Process>, procs: RefMutPosition<'_, ProcessList>) {
+    pub(super) fn add_child(&self, child: &Arc<Process>, procs: ProofMut<'_, ProcessList>) {
         assert!(self
             .inner
             .access_mut(procs)
@@ -249,7 +247,7 @@ impl Process {
             .is_none());
     }
 
-    pub(super) fn add_thread(&self, thread: &Arc<Thread>, procs: RefMutPosition<'_, ProcessList>) {
+    pub(super) fn add_thread(&self, thread: &Arc<Thread>, procs: ProofMut<'_, ProcessList>) {
         assert!(self
             .inner
             .access_mut(procs)
@@ -273,7 +271,7 @@ impl Process {
 
                 if self
                     .inner
-                    .access(waits.process_list.as_pos())
+                    .access(waits.process_list.prove())
                     .children
                     .is_empty()
                 {
@@ -295,7 +293,7 @@ impl Process {
             procs.remove_process(wait_object.pid);
             assert!(self
                 .inner
-                .access_mut(procs.as_pos_mut())
+                .access_mut(procs.prove_mut())
                 .children
                 .remove(&wait_object.pid)
                 .is_some());
@@ -322,7 +320,7 @@ impl Process {
         {
             let _old_session = unsafe { self.session.swap(Some(session.clone())) }.unwrap();
             let old_pgroup = unsafe { self.pgroup.swap(Some(pgroup.clone())) }.unwrap();
-            old_pgroup.remove_member(self.pid, process_list.as_pos_mut());
+            old_pgroup.remove_member(self.pid, process_list.prove_mut());
             rcu_sync();
         }
 
@@ -354,7 +352,7 @@ impl Process {
                 return Ok(());
             }
 
-            new_pgroup.add_member(self, procs.as_pos_mut());
+            new_pgroup.add_member(self, procs.prove_mut());
 
             new_pgroup
         } else {
@@ -369,7 +367,7 @@ impl Process {
                 .build(procs)
         };
 
-        pgroup.remove_member(self.pid, procs.as_pos_mut());
+        pgroup.remove_member(self.pid, procs.prove_mut());
         {
             let _old_pgroup = unsafe { self.pgroup.swap(Some(new_pgroup)) }.unwrap();
             rcu_sync();
@@ -391,7 +389,7 @@ impl Process {
             let child = {
                 // If `pid` refers to one of our children, the thread leaders must be
                 // in out children list.
-                let children = &self.inner.access(procs.as_pos()).children;
+                let children = &self.inner.access(procs.prove()).children;
                 let child = {
                     let child = children.get(&pid);
                     child.and_then(Weak::upgrade).ok_or(ESRCH)?
@@ -399,7 +397,7 @@ impl Process {
 
                 // Changing the process group of a child is only allowed
                 // if we are in the same session.
-                if child.session(procs.as_pos()).sid != self.session(procs.as_pos()).sid {
+                if child.session(procs.prove()).sid != self.session(procs.prove()).sid {
                     return Err(EPERM);
                 }
 
@@ -413,22 +411,19 @@ impl Process {
     }
 
     /// Provide locked (consistent) access to the session.
-    pub fn session<'r>(&'r self, _procs: RefPosition<'r, ProcessList>) -> BorrowedArc<'r, Session> {
+    pub fn session<'r>(&'r self, _procs: Proof<'r, ProcessList>) -> BorrowedArc<'r, Session> {
         // SAFETY: We are holding the process list lock.
         unsafe { self.session.load_locked() }.unwrap()
     }
 
     /// Provide locked (consistent) access to the process group.
-    pub fn pgroup<'r>(
-        &'r self,
-        _procs: RefPosition<'r, ProcessList>,
-    ) -> BorrowedArc<'r, ProcessGroup> {
+    pub fn pgroup<'r>(&'r self, _procs: Proof<'r, ProcessList>) -> BorrowedArc<'r, ProcessGroup> {
         // SAFETY: We are holding the process list lock.
         unsafe { self.pgroup.load_locked() }.unwrap()
     }
 
     /// Provide locked (consistent) access to the parent process.
-    pub fn parent<'r>(&'r self, _procs: RefPosition<'r, ProcessList>) -> BorrowedArc<'r, Process> {
+    pub fn parent<'r>(&'r self, _procs: Proof<'r, ProcessList>) -> BorrowedArc<'r, Process> {
         // SAFETY: We are holding the process list lock.
         unsafe { self.parent.load_locked() }.unwrap()
     }
@@ -448,7 +443,7 @@ impl Process {
         self.parent.load()
     }
 
-    pub fn notify(&self, wait: WaitObject, procs: RefPosition<'_, ProcessList>) {
+    pub fn notify(&self, wait: WaitObject, procs: Proof<'_, ProcessList>) {
         self.wait_list.notify(wait);
         self.raise(Signal::SIGCHLD, procs);
     }
@@ -553,7 +548,7 @@ impl NotifyBatch<'_, '_, '_> {
     }
 
     /// Finish the batch and notify all if we have notified some processes.
-    pub fn finish(mut self, procs: RefPosition<'_, ProcessList>) {
+    pub fn finish(mut self, procs: Proof<'_, ProcessList>) {
         if self.needs_notify {
             self.cv.notify_all();
             self.process.raise(Signal::SIGCHLD, procs);

+ 5 - 14
src/kernel/task/process_group.rs

@@ -1,14 +1,9 @@
+use super::{Process, ProcessList, Session, Signal};
 use alloc::{
     collections::btree_map::BTreeMap,
     sync::{Arc, Weak},
 };
-
-use crate::{
-    prelude::*,
-    sync::{RefMutPosition, RefPosition},
-};
-
-use super::{Process, ProcessList, Session, Signal};
+use eonix_sync::{Locked, Proof, ProofMut};
 
 pub struct ProcessGroupBuilder {
     pgid: Option<u32>,
@@ -64,11 +59,7 @@ impl ProcessGroupBuilder {
 }
 
 impl ProcessGroup {
-    pub(super) fn add_member(
-        &self,
-        process: &Arc<Process>,
-        procs: RefMutPosition<'_, ProcessList>,
-    ) {
+    pub(super) fn add_member(&self, process: &Arc<Process>, procs: ProofMut<'_, ProcessList>) {
         assert!(self
             .processes
             .access_mut(procs)
@@ -76,7 +67,7 @@ impl ProcessGroup {
             .is_none());
     }
 
-    pub(super) fn remove_member(&self, pid: u32, procs: RefMutPosition<'_, ProcessList>) {
+    pub(super) fn remove_member(&self, pid: u32, procs: ProofMut<'_, ProcessList>) {
         let processes = self.processes.access_mut(procs);
         assert!(processes.remove(&pid).is_some());
         if processes.is_empty() {
@@ -87,7 +78,7 @@ impl ProcessGroup {
         }
     }
 
-    pub fn raise(&self, signal: Signal, procs: RefPosition<'_, ProcessList>) {
+    pub fn raise(&self, signal: Signal, procs: Proof<'_, ProcessList>) {
         let processes = self.processes.access(procs);
         for process in processes.values().map(|p| p.upgrade().unwrap()) {
             process.raise(signal, procs);

+ 11 - 17
src/kernel/task/process_list.rs

@@ -1,19 +1,13 @@
+use super::{Process, ProcessGroup, Session, Signal, Thread, WaitObject, WaitType};
+use crate::{prelude::*, rcu::rcu_sync};
 use alloc::{
     collections::btree_map::BTreeMap,
     sync::{Arc, Weak},
 };
 use bindings::KERNEL_PML4;
-
-use crate::{
-    prelude::*,
-    rcu::rcu_sync,
-    sync::{AsRefMutPosition as _, AsRefPosition as _},
-};
-
+use eonix_sync::{AsProof as _, AsProofMut as _};
 use lazy_static::lazy_static;
 
-use super::{Process, ProcessGroup, Session, Signal, Thread, WaitObject, WaitType};
-
 pub struct ProcessList {
     /// The init process.
     init: Option<Arc<Process>>,
@@ -84,7 +78,7 @@ impl ProcessList {
             let session = unsafe { thread.process.session.swap(None) }.unwrap();
             let pgroup = unsafe { thread.process.pgroup.swap(None) }.unwrap();
             let _parent = unsafe { thread.process.parent.swap(None) }.unwrap();
-            pgroup.remove_member(pid, self.as_pos_mut());
+            pgroup.remove_member(pid, self.prove_mut());
             rcu_sync();
 
             if Arc::strong_count(&pgroup) == 1 {
@@ -132,7 +126,7 @@ impl ProcessList {
             panic!("init exited");
         }
 
-        let inner = process.inner.access_mut(self.as_pos_mut());
+        let inner = process.inner.access_mut(self.prove_mut());
         // TODO!!!!!!: When we are killing multiple threads, we need to wait until all
         // the threads are stopped then proceed.
         for thread in inner.threads.values().map(|t| t.upgrade().unwrap()) {
@@ -142,8 +136,8 @@ impl ProcessList {
         }
 
         // If we are the session leader, we should drop the control terminal.
-        if process.session(self.as_pos()).sid == process.pid {
-            if let Some(terminal) = process.session(self.as_pos()).drop_control_terminal() {
+        if process.session(self.prove()).sid == process.pid {
+            if let Some(terminal) = process.session(self.prove()).drop_control_terminal() {
                 terminal.drop_session();
             }
         }
@@ -162,7 +156,7 @@ impl ProcessList {
                 let child = child.upgrade().unwrap();
                 // SAFETY: `child.parent` must be ourself. So we don't need to free it.
                 unsafe { child.parent.swap(Some(init.clone())) };
-                init.add_child(&child, self.as_pos_mut());
+                init.add_child(&child, self.prove_mut());
 
                 false
             });
@@ -174,14 +168,14 @@ impl ProcessList {
             .drain_exited()
             .into_iter()
             .for_each(|item| init_notify.notify(item));
-        init_notify.finish(self.as_pos());
+        init_notify.finish(self.prove());
 
-        process.parent(self.as_pos()).notify(
+        process.parent(self.prove()).notify(
             WaitObject {
                 pid: process.pid,
                 code: status,
             },
-            self.as_pos(),
+            self.prove(),
         );
     }
 }

+ 8 - 17
src/kernel/task/session.rs

@@ -1,16 +1,11 @@
+use super::{Process, ProcessGroup, ProcessList, Signal, Thread};
+use crate::{kernel::Terminal, prelude::*};
 use alloc::{
     collections::btree_map::BTreeMap,
     sync::{Arc, Weak},
 };
 use bindings::EPERM;
-
-use crate::{
-    kernel::Terminal,
-    prelude::*,
-    sync::{AsRefMutPosition as _, AsRefPosition as _, RefMutPosition, RefPosition},
-};
-
-use super::{Process, ProcessGroup, ProcessList, Signal, Thread};
+use eonix_sync::{AsProof as _, AsProofMut as _, Locked, Proof, ProofMut};
 
 #[derive(Debug)]
 struct SessionJobControl {
@@ -51,12 +46,12 @@ impl Session {
     }
 
     pub(super) fn add_member(&self, procs: &mut ProcessList, pgroup: &Arc<ProcessGroup>) {
-        let groups = self.groups.access_mut(procs.as_pos_mut());
+        let groups = self.groups.access_mut(procs.prove_mut());
         let old = groups.insert(pgroup.pgid, Arc::downgrade(pgroup));
         assert!(old.is_none(), "Process group already exists");
     }
 
-    pub(super) fn remove_member(&self, pgid: u32, procs: RefMutPosition<'_, ProcessList>) {
+    pub(super) fn remove_member(&self, pgid: u32, procs: ProofMut<'_, ProcessList>) {
         assert!(self.groups.access_mut(procs).remove(&pgid).is_some());
     }
 
@@ -66,11 +61,7 @@ impl Session {
 
     /// Set the foreground process group identified by `pgid`.
     /// The process group must belong to the session.
-    pub fn set_foreground_pgid(
-        &self,
-        pgid: u32,
-        procs: RefPosition<'_, ProcessList>,
-    ) -> KResult<()> {
+    pub fn set_foreground_pgid(&self, pgid: u32, procs: Proof<'_, ProcessList>) -> KResult<()> {
         if let Some(group) = self.groups.access(procs).get(&pgid) {
             self.job_control.lock().foreground = group.clone();
             Ok(())
@@ -87,7 +78,7 @@ impl Session {
         self: &Arc<Self>,
         terminal: &Arc<Terminal>,
         forced: bool,
-        procs: RefPosition<'_, ProcessList>,
+        procs: Proof<'_, ProcessList>,
     ) -> KResult<()> {
         let mut job_control = self.job_control.lock();
         if let Some(_) = job_control.control_terminal.as_ref() {
@@ -115,7 +106,7 @@ impl Session {
     pub fn raise_foreground(&self, signal: Signal) {
         if let Some(fg) = self.foreground() {
             let procs = ProcessList::get().lock_shared();
-            fg.raise(signal, procs.as_pos());
+            fg.raise(signal, procs.prove());
         }
     }
 }

+ 3 - 3
src/kernel/task/signal.rs

@@ -6,13 +6,13 @@ use crate::{
         user::{dataflow::UserBuffer, UserPointer},
     },
     prelude::*,
-    sync::AsRefPosition as _,
 };
 use alloc::collections::{binary_heap::BinaryHeap, btree_map::BTreeMap};
 use arch::{ExtendedContext, InterruptContext};
 use bindings::{EFAULT, EINVAL};
 use core::{cmp::Reverse, task::Waker};
 use eonix_runtime::{scheduler::Scheduler, task::Task};
+use eonix_sync::AsProof as _;
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
 pub struct Signal(u32);
@@ -413,7 +413,7 @@ impl SignalList {
                                 pid: thread.process.pid,
                                 code: WaitType::Stopped(signal),
                             },
-                            ProcessList::get().lock_shared().as_pos(),
+                            ProcessList::get().lock_shared().prove(),
                         );
                     }
 
@@ -436,7 +436,7 @@ impl SignalList {
                                 pid: thread.process.pid,
                                 code: WaitType::Continued,
                             },
-                            ProcessList::get().lock_shared().as_pos(),
+                            ProcessList::get().lock_shared().prove(),
                         );
                     }
                 }

+ 2 - 2
src/kernel/task/thread.rs

@@ -10,7 +10,6 @@ use crate::{
         vfs::{filearray::FileArray, FsContext},
     },
     prelude::*,
-    sync::AsRefMutPosition as _,
 };
 use alloc::sync::Arc;
 use arch::{InterruptContext, UserTLS, _arch_fork_return};
@@ -26,6 +25,7 @@ use eonix_runtime::{
     context::ExecutionContext,
     run::{Contexted, PinRun, RunState},
 };
+use eonix_sync::AsProofMut as _;
 use pointers::BorrowedArc;
 
 struct CurrentThread {
@@ -217,7 +217,7 @@ impl ThreadBuilder {
         });
 
         process_list.add_thread(&thread);
-        process.add_thread(&thread, process_list.as_pos_mut());
+        process.add_thread(&thread, process_list.prove_mut());
         thread
     }
 }

+ 3 - 6
src/kernel/terminal.rs

@@ -2,11 +2,7 @@ use super::{
     task::{ProcessList, Session, Signal, Thread},
     user::{UserPointer, UserPointerMut},
 };
-use crate::{
-    io::Buffer,
-    prelude::*,
-    sync::{AsRefPosition as _, CondVar},
-};
+use crate::{io::Buffer, prelude::*, sync::CondVar};
 use alloc::{
     collections::vec_deque::VecDeque,
     sync::{Arc, Weak},
@@ -14,6 +10,7 @@ use alloc::{
 use bindings::{EINTR, ENOTTY, EPERM};
 use bitflags::bitflags;
 use eonix_log::ConsoleWrite;
+use eonix_sync::AsProof as _;
 
 const BUFFER_SIZE: usize = 4096;
 
@@ -614,7 +611,7 @@ impl Terminal {
                 let session = inner.session.upgrade();
 
                 if let Some(session) = session {
-                    session.set_foreground_pgid(pgid, procs.as_pos())
+                    session.set_foreground_pgid(pgid, procs.prove())
                 } else {
                     Err(ENOTTY)
                 }

+ 1 - 1
src/prelude.rs

@@ -22,7 +22,7 @@ pub(crate) use alloc::{boxed::Box, string::String, vec, vec::Vec};
 
 pub(crate) use core::{any::Any, fmt::Write, marker::PhantomData, str};
 
-pub use crate::sync::{Locked, Mutex, RwSemaphore, Spin};
+pub use crate::sync::{Mutex, RwSemaphore, Spin};
 
 #[allow(dead_code)]
 pub trait AsAny: Send + Sync {

+ 0 - 19
src/sync.rs

@@ -1,6 +1,5 @@
 mod arcswap;
 mod condvar;
-mod locked;
 pub mod semaphore;
 
 pub use eonix_sync::{Guard, Lock, Spin, SpinStrategy};
@@ -21,31 +20,13 @@ pub extern "C" fn r_preempt_count() -> usize {
 }
 
 pub type Mutex<T> = Lock<T, semaphore::SemaphoreStrategy<1>>;
-#[allow(dead_code)]
-pub type Semaphore<T> = Lock<T, semaphore::SemaphoreStrategy>;
 pub type RwSemaphore<T> = Lock<T, semaphore::RwSemaphoreStrategy>;
 
-#[allow(dead_code)]
 pub type SpinGuard<'lock, T> = Guard<'lock, T, SpinStrategy, SpinStrategy, true>;
-
-#[allow(dead_code)]
-pub type MutexGuard<'lock, T> =
-    Guard<'lock, T, semaphore::SemaphoreStrategy<1>, semaphore::SemaphoreStrategy<1>, true>;
-
-#[allow(dead_code)]
-pub type SemGuard<'lock, T> =
-    Guard<'lock, T, semaphore::SemaphoreStrategy, semaphore::SemaphoreStrategy, true>;
-
-#[allow(dead_code)]
 pub type RwSemReadGuard<'lock, T> =
     Guard<'lock, T, semaphore::RwSemaphoreStrategy, semaphore::RwSemaphoreStrategy, false>;
 
-#[allow(dead_code)]
-pub type RwSemWriteGuard<'lock, T> =
-    Guard<'lock, T, semaphore::RwSemaphoreStrategy, semaphore::RwSemaphoreStrategy, true>;
-
 pub type CondVar = condvar::CondVar<true>;
 pub type UCondVar = condvar::CondVar<false>;
 
 pub use arcswap::ArcSwap;
-pub use locked::{AsRefMutPosition, AsRefPosition, Locked, RefMutPosition, RefPosition};

+ 0 - 151
src/sync/locked.rs

@@ -1,151 +0,0 @@
-use core::{cell::UnsafeCell, marker::PhantomData};
-use eonix_sync::{Guard, LockStrategy};
-
-pub struct RefMutPosition<'pos, T: ?Sized> {
-    address: *const T,
-    _phantom: PhantomData<&'pos ()>,
-}
-
-pub struct RefPosition<'pos, T: ?Sized> {
-    address: *const T,
-    _phantom: PhantomData<&'pos ()>,
-}
-
-pub trait AsRefMutPosition<'guard, 'pos, T: ?Sized>: 'guard {
-    fn as_pos_mut(&self) -> RefMutPosition<'pos, T>
-    where
-        'guard: 'pos;
-}
-
-pub trait AsRefPosition<'guard, 'pos, T: ?Sized>: 'guard {
-    fn as_pos(&self) -> RefPosition<'pos, T>
-    where
-        'guard: 'pos;
-}
-
-unsafe impl<T: Sized + Send, U: ?Sized> Send for Locked<T, U> {}
-unsafe impl<T: Sized + Send + Sync, U: ?Sized> Sync for Locked<T, U> {}
-pub struct Locked<T: Sized, U: ?Sized> {
-    inner: UnsafeCell<T>,
-    guard: *const U,
-}
-
-impl<T: ?Sized> Copy for RefPosition<'_, T> {}
-impl<T: ?Sized> Clone for RefPosition<'_, T> {
-    fn clone(&self) -> Self {
-        Self {
-            address: self.address,
-            _phantom: self._phantom,
-        }
-    }
-}
-
-impl<T: ?Sized> Copy for RefMutPosition<'_, T> {}
-impl<T: ?Sized> Clone for RefMutPosition<'_, T> {
-    fn clone(&self) -> Self {
-        Self {
-            address: self.address,
-            _phantom: self._phantom,
-        }
-    }
-}
-
-impl<'lock, 'pos, T: ?Sized> AsRefMutPosition<'lock, 'pos, T> for &'lock mut T {
-    fn as_pos_mut(&self) -> RefMutPosition<'pos, T>
-    where
-        'lock: 'pos,
-    {
-        RefMutPosition {
-            address: *self as *const T,
-            _phantom: PhantomData,
-        }
-    }
-}
-
-impl<'lock, 'pos, T, S, L> AsRefMutPosition<'lock, 'pos, T> for Guard<'lock, T, S, L, true>
-where
-    T: ?Sized,
-    S: LockStrategy + 'lock,
-    L: LockStrategy + 'lock,
-{
-    fn as_pos_mut(&self) -> RefMutPosition<'pos, T>
-    where
-        'lock: 'pos,
-    {
-        RefMutPosition {
-            address: &raw const **self,
-            _phantom: PhantomData,
-        }
-    }
-}
-
-impl<'lock, 'pos, T: ?Sized> AsRefPosition<'lock, 'pos, T> for &'lock T {
-    fn as_pos(&self) -> RefPosition<'pos, T>
-    where
-        'lock: 'pos,
-    {
-        RefPosition {
-            address: *self as *const T,
-            _phantom: PhantomData,
-        }
-    }
-}
-
-impl<'lock, 'pos, T: ?Sized> AsRefPosition<'lock, 'pos, T> for &'lock mut T {
-    fn as_pos(&self) -> RefPosition<'pos, T>
-    where
-        'lock: 'pos,
-    {
-        RefPosition {
-            address: *self as *const T,
-            _phantom: PhantomData,
-        }
-    }
-}
-
-impl<'lock, 'pos, T, S, L, const B: bool> AsRefPosition<'lock, 'pos, T> for Guard<'lock, T, S, L, B>
-where
-    T: ?Sized,
-    S: LockStrategy + 'lock,
-    L: LockStrategy + 'lock,
-{
-    fn as_pos(&self) -> RefPosition<'pos, T>
-    where
-        'lock: 'pos,
-    {
-        RefPosition {
-            address: &raw const **self,
-            _phantom: PhantomData,
-        }
-    }
-}
-
-impl<T: Sized, U: ?Sized> core::fmt::Debug for Locked<T, U> {
-    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
-        f.debug_struct("Locked")
-            .field("value", &self.inner)
-            .field("guard", &self.guard)
-            .finish()
-    }
-}
-
-impl<T: Sized + Sync, U: ?Sized> Locked<T, U> {
-    pub fn new(value: T, guard: *const U) -> Self {
-        Self {
-            inner: UnsafeCell::new(value),
-            guard,
-        }
-    }
-
-    pub fn access<'lt>(&'lt self, guard: RefPosition<'lt, U>) -> &'lt T {
-        assert_eq!(self.guard, guard.address, "Locked: Wrong guard");
-        // SAFETY: The guard protects the shared access to the inner value.
-        unsafe { self.inner.get().as_ref() }.unwrap()
-    }
-
-    pub fn access_mut<'lt>(&'lt self, guard: RefMutPosition<'lt, U>) -> &'lt mut T {
-        assert_eq!(self.guard, guard.address, "Locked: Wrong guard");
-        // SAFETY: The guard protects the exclusive access to the inner value.
-        unsafe { self.inner.get().as_mut() }.unwrap()
-    }
-}