asterinas/framework/aster-frame/src/sync/rcu/mod.rs

103 lines
2.2 KiB
Rust

//! Read-copy update (RCU).
use core::marker::PhantomData;
use core::ops::Deref;
use core::sync::atomic::{
AtomicPtr,
Ordering::{AcqRel, Acquire},
};
use self::monitor::RcuMonitor;
use crate::prelude::*;
use crate::sync::WaitQueue;
mod monitor;
mod owner_ptr;
pub use owner_ptr::OwnerPtr;
pub struct Rcu<P: OwnerPtr> {
ptr: AtomicPtr<<P as OwnerPtr>::Target>,
marker: PhantomData<P::Target>,
}
impl<P: OwnerPtr> Rcu<P> {
pub fn new(ptr: P) -> Self {
let ptr = AtomicPtr::new(OwnerPtr::into_raw(ptr) as *mut _);
Self {
ptr,
marker: PhantomData,
}
}
pub fn get(&self) -> RcuReadGuard<'_, P> {
let obj = unsafe { &*self.ptr.load(Acquire) };
RcuReadGuard { obj, rcu: self }
}
}
impl<P: OwnerPtr + Send> Rcu<P> {
pub fn replace(&self, new_ptr: P) -> RcuReclaimer<P> {
let new_ptr = <P as OwnerPtr>::into_raw(new_ptr) as *mut _;
let old_ptr = {
let old_raw_ptr = self.ptr.swap(new_ptr, AcqRel);
unsafe { <P as OwnerPtr>::from_raw(old_raw_ptr) }
};
RcuReclaimer { ptr: old_ptr }
}
}
pub struct RcuReadGuard<'a, P: OwnerPtr> {
obj: &'a <P as OwnerPtr>::Target,
rcu: &'a Rcu<P>,
}
impl<'a, P: OwnerPtr> Deref for RcuReadGuard<'a, P> {
type Target = <P as OwnerPtr>::Target;
fn deref(&self) -> &Self::Target {
self.obj
}
}
#[repr(transparent)]
pub struct RcuReclaimer<P> {
ptr: P,
}
impl<P: Send + 'static> RcuReclaimer<P> {
pub fn delay(mut self) {
let ptr: P = unsafe {
let ptr = core::mem::replace(&mut self.ptr, core::mem::uninitialized());
core::mem::forget(self);
ptr
};
get_singleton().after_grace_period(move || {
drop(ptr);
});
}
}
impl<P> Drop for RcuReclaimer<P> {
fn drop(&mut self) {
let wq = Arc::new(WaitQueue::new());
get_singleton().after_grace_period({
let wq = wq.clone();
move || {
wq.wake_one();
}
});
wq.wait_until(|| Some(0u8));
}
}
pub unsafe fn pass_quiescent_state() {
get_singleton().pass_quiescent_state()
}
fn get_singleton() -> &'static RcuMonitor {
todo!()
}