mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-22 00:43:24 +00:00
Enable RCU to read reference to stored pointers
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
36f6f9bcd4
commit
a21e895102
@ -55,12 +55,9 @@ impl AnyConsoleDevice for ConsoleDevice {
|
|||||||
fn register_callback(&self, callback: &'static ConsoleCallback) {
|
fn register_callback(&self, callback: &'static ConsoleCallback) {
|
||||||
loop {
|
loop {
|
||||||
let callbacks = self.callbacks.read();
|
let callbacks = self.callbacks.read();
|
||||||
let mut callbacks_cloned = callbacks.clone();
|
let mut callbacks_cloned = callbacks.get().clone();
|
||||||
callbacks_cloned.push(callback);
|
callbacks_cloned.push(callback);
|
||||||
if callbacks
|
if callbacks.compare_exchange(callbacks_cloned).is_ok() {
|
||||||
.compare_exchange(Box::new(callbacks_cloned))
|
|
||||||
.is_ok()
|
|
||||||
{
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// Contention on pushing, retry.
|
// Contention on pushing, retry.
|
||||||
@ -150,7 +147,7 @@ impl ConsoleDevice {
|
|||||||
self.receive_buffer.sync(0..len as usize).unwrap();
|
self.receive_buffer.sync(0..len as usize).unwrap();
|
||||||
|
|
||||||
let callbacks = self.callbacks.read();
|
let callbacks = self.callbacks.read();
|
||||||
for callback in callbacks.iter() {
|
for callback in callbacks.get().iter() {
|
||||||
let mut reader = self.receive_buffer.reader().unwrap();
|
let mut reader = self.receive_buffer.reader().unwrap();
|
||||||
reader.limit(len as usize);
|
reader.limit(len as usize);
|
||||||
callback(reader);
|
callback(reader);
|
||||||
|
@ -26,10 +26,7 @@ pub(super) fn register_callback(func: fn()) {
|
|||||||
Some(callbacks_vec) => {
|
Some(callbacks_vec) => {
|
||||||
let mut callbacks_cloned = callbacks_vec.clone();
|
let mut callbacks_cloned = callbacks_vec.clone();
|
||||||
callbacks_cloned.push(func);
|
callbacks_cloned.push(func);
|
||||||
if callbacks
|
if callbacks.compare_exchange(Some(callbacks_cloned)).is_ok() {
|
||||||
.compare_exchange(Some(Box::new(callbacks_cloned)))
|
|
||||||
.is_ok()
|
|
||||||
{
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@ pub(crate) use self::{guard::GuardTransfer, rcu::finish_grace_period};
|
|||||||
pub use self::{
|
pub use self::{
|
||||||
guard::{LocalIrqDisabled, PreemptDisabled, WriteIrqDisabled},
|
guard::{LocalIrqDisabled, PreemptDisabled, WriteIrqDisabled},
|
||||||
mutex::{ArcMutexGuard, Mutex, MutexGuard},
|
mutex::{ArcMutexGuard, Mutex, MutexGuard},
|
||||||
rcu::{OwnerPtr, Rcu, RcuOption, RcuReadGuard},
|
rcu::{non_null, Rcu, RcuOption, RcuOptionReadGuard, RcuReadGuard},
|
||||||
rwarc::{RoArc, RwArc},
|
rwarc::{RoArc, RwArc},
|
||||||
rwlock::{
|
rwlock::{
|
||||||
ArcRwLockReadGuard, ArcRwLockUpgradeableGuard, ArcRwLockWriteGuard, RwLock,
|
ArcRwLockReadGuard, ArcRwLockUpgradeableGuard, ArcRwLockWriteGuard, RwLock,
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
|
|
||||||
use core::{
|
use core::{
|
||||||
marker::PhantomData,
|
marker::PhantomData,
|
||||||
ops::Deref,
|
|
||||||
ptr::NonNull,
|
ptr::NonNull,
|
||||||
sync::atomic::{
|
sync::atomic::{
|
||||||
AtomicPtr,
|
AtomicPtr,
|
||||||
@ -12,20 +11,19 @@ use core::{
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use non_null::NonNullPtr;
|
||||||
use spin::once::Once;
|
use spin::once::Once;
|
||||||
|
|
||||||
use self::monitor::RcuMonitor;
|
use self::monitor::RcuMonitor;
|
||||||
use crate::task::{atomic_mode::AsAtomicModeGuard, disable_preempt, DisabledPreemptGuard};
|
use crate::task::{atomic_mode::AsAtomicModeGuard, disable_preempt, DisabledPreemptGuard};
|
||||||
|
|
||||||
mod monitor;
|
mod monitor;
|
||||||
mod owner_ptr;
|
pub mod non_null;
|
||||||
|
|
||||||
pub use owner_ptr::OwnerPtr;
|
|
||||||
|
|
||||||
/// A Read-Copy Update (RCU) cell for sharing a pointer between threads.
|
/// A Read-Copy Update (RCU) cell for sharing a pointer between threads.
|
||||||
///
|
///
|
||||||
/// The pointer should be a owning pointer with type `P`, which implements
|
/// The pointer should be a non-null pointer with type `P`, which implements
|
||||||
/// [`OwnerPtr`]. For example, `P` can be `Box<T>` or `Arc<T>`.
|
/// [`NonNullPtr`]. For example, `P` can be `Box<T>` or `Arc<T>`.
|
||||||
///
|
///
|
||||||
/// # Overview
|
/// # Overview
|
||||||
///
|
///
|
||||||
@ -58,12 +56,12 @@ pub use owner_ptr::OwnerPtr;
|
|||||||
///
|
///
|
||||||
/// assert_eq!(*rcu_guard, Some(&43));
|
/// assert_eq!(*rcu_guard, Some(&43));
|
||||||
/// ```
|
/// ```
|
||||||
pub struct Rcu<P: OwnerPtr>(RcuInner<P>);
|
pub struct Rcu<P: NonNullPtr>(RcuInner<P>);
|
||||||
|
|
||||||
/// A guard that allows access to the pointed data protected by a [`Rcu`].
|
/// A guard that allows access to the pointed data protected by a [`Rcu`].
|
||||||
#[clippy::has_significant_drop]
|
#[clippy::has_significant_drop]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub struct RcuReadGuard<'a, P: OwnerPtr>(RcuReadGuardInner<'a, P>);
|
pub struct RcuReadGuard<'a, P: NonNullPtr>(RcuReadGuardInner<'a, P>);
|
||||||
|
|
||||||
/// A Read-Copy Update (RCU) cell for sharing a _nullable_ pointer.
|
/// A Read-Copy Update (RCU) cell for sharing a _nullable_ pointer.
|
||||||
///
|
///
|
||||||
@ -98,37 +96,32 @@ pub struct RcuReadGuard<'a, P: OwnerPtr>(RcuReadGuardInner<'a, P>);
|
|||||||
/// assert_eq!(*rcu_guard, 43);
|
/// assert_eq!(*rcu_guard, 43);
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub struct RcuOption<P: OwnerPtr>(RcuInner<P>);
|
pub struct RcuOption<P: NonNullPtr>(RcuInner<P>);
|
||||||
|
|
||||||
/// A guard that allows access to the pointed data protected by a [`RcuOption`].
|
/// A guard that allows access to the pointed data protected by a [`RcuOption`].
|
||||||
#[clippy::has_significant_drop]
|
#[clippy::has_significant_drop]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub struct RcuOptionReadGuard<'a, P: OwnerPtr>(RcuReadGuardInner<'a, P>);
|
pub struct RcuOptionReadGuard<'a, P: NonNullPtr>(RcuReadGuardInner<'a, P>);
|
||||||
|
|
||||||
/// The inner implementation of both [`Rcu`] and [`RcuOption`].
|
/// The inner implementation of both [`Rcu`] and [`RcuOption`].
|
||||||
struct RcuInner<P: OwnerPtr> {
|
struct RcuInner<P: NonNullPtr> {
|
||||||
ptr: AtomicPtr<<P as OwnerPtr>::Target>,
|
ptr: AtomicPtr<<P as NonNullPtr>::Target>,
|
||||||
// We want to implement Send and Sync explicitly.
|
// We want to implement Send and Sync explicitly.
|
||||||
// Having a pointer field prevents them from being implemented
|
// Having a pointer field prevents them from being implemented
|
||||||
// automatically by the compiler.
|
// automatically by the compiler.
|
||||||
_marker: PhantomData<*const P::Target>,
|
_marker: PhantomData<*const P::Target>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// SAFETY: It is apparent that if `P::Target` is `Send`, then `Rcu<P>` is `Send`.
|
// SAFETY: It is apparent that if `P` is `Send`, then `Rcu<P>` is `Send`.
|
||||||
unsafe impl<P: OwnerPtr> Send for RcuInner<P> where <P as OwnerPtr>::Target: Send {}
|
unsafe impl<P: NonNullPtr> Send for RcuInner<P> where P: Send {}
|
||||||
|
|
||||||
// SAFETY: To implement `Sync` for `Rcu<P>`, we need to meet two conditions:
|
// SAFETY: To implement `Sync` for `Rcu<P>`, we need to meet two conditions:
|
||||||
// 1. `P::Target` must be `Sync` because `Rcu::get` allows concurrent access.
|
// 1. `P` must be `Sync` because `Rcu::get` allows concurrent access.
|
||||||
// 2. `P::Target` must be `Send` because `Rcu::update` may obtain an object
|
// 2. `P` must be `Send` because `Rcu::update` may obtain an object
|
||||||
// of `P` created on another thread.
|
// of `P` created on another thread.
|
||||||
unsafe impl<P: OwnerPtr> Sync for RcuInner<P>
|
unsafe impl<P: NonNullPtr> Sync for RcuInner<P> where P: Send + Sync {}
|
||||||
where
|
|
||||||
<P as OwnerPtr>::Target: Send + Sync,
|
|
||||||
P: Send,
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<P: OwnerPtr> RcuInner<P> {
|
impl<P: NonNullPtr> RcuInner<P> {
|
||||||
const fn new_none() -> Self {
|
const fn new_none() -> Self {
|
||||||
Self {
|
Self {
|
||||||
ptr: AtomicPtr::new(core::ptr::null_mut()),
|
ptr: AtomicPtr::new(core::ptr::null_mut()),
|
||||||
@ -137,7 +130,7 @@ impl<P: OwnerPtr> RcuInner<P> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn new(pointer: P) -> Self {
|
fn new(pointer: P) -> Self {
|
||||||
let ptr = <P as OwnerPtr>::into_raw(pointer).as_ptr();
|
let ptr = <P as NonNullPtr>::into_raw(pointer).as_ptr();
|
||||||
let ptr = AtomicPtr::new(ptr);
|
let ptr = AtomicPtr::new(ptr);
|
||||||
Self {
|
Self {
|
||||||
ptr,
|
ptr,
|
||||||
@ -147,7 +140,7 @@ impl<P: OwnerPtr> RcuInner<P> {
|
|||||||
|
|
||||||
fn update(&self, new_ptr: Option<P>) {
|
fn update(&self, new_ptr: Option<P>) {
|
||||||
let new_ptr = if let Some(new_ptr) = new_ptr {
|
let new_ptr = if let Some(new_ptr) = new_ptr {
|
||||||
<P as OwnerPtr>::into_raw(new_ptr).as_ptr()
|
<P as NonNullPtr>::into_raw(new_ptr).as_ptr()
|
||||||
} else {
|
} else {
|
||||||
core::ptr::null_mut()
|
core::ptr::null_mut()
|
||||||
};
|
};
|
||||||
@ -169,10 +162,7 @@ impl<P: OwnerPtr> RcuInner<P> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_with<'a>(
|
fn read_with<'a>(&'a self, guard: &'a dyn AsAtomicModeGuard) -> Option<P::Ref<'a>> {
|
||||||
&'a self,
|
|
||||||
guard: &'a dyn AsAtomicModeGuard,
|
|
||||||
) -> Option<&'a <P as OwnerPtr>::Target> {
|
|
||||||
// Ensure that a real atomic-mode guard is obtained.
|
// Ensure that a real atomic-mode guard is obtained.
|
||||||
let _atomic_mode_guard = guard.as_atomic_mode_guard();
|
let _atomic_mode_guard = guard.as_atomic_mode_guard();
|
||||||
|
|
||||||
@ -185,17 +175,17 @@ impl<P: OwnerPtr> RcuInner<P> {
|
|||||||
// 2. The `_atomic_mode_guard` guarantees atomic mode for the duration of
|
// 2. The `_atomic_mode_guard` guarantees atomic mode for the duration of
|
||||||
// lifetime `'a`, the pointer is valid because other writers won't release
|
// lifetime `'a`, the pointer is valid because other writers won't release
|
||||||
// the allocation until this task passes the quiescent state.
|
// the allocation until this task passes the quiescent state.
|
||||||
Some(unsafe { &*obj_ptr })
|
NonNull::new(obj_ptr).map(|ptr| unsafe { P::raw_as_ref(ptr) })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<P: OwnerPtr> Drop for RcuInner<P> {
|
impl<P: NonNullPtr> Drop for RcuInner<P> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
let ptr = self.ptr.load(Acquire);
|
let ptr = self.ptr.load(Acquire);
|
||||||
if let Some(p) = NonNull::new(ptr) {
|
if let Some(p) = NonNull::new(ptr) {
|
||||||
// SAFETY: It was previously returned by `into_raw` when creating
|
// SAFETY: It was previously returned by `into_raw` when creating
|
||||||
// the RCU primitive.
|
// the RCU primitive.
|
||||||
let pointer = unsafe { <P as OwnerPtr>::from_raw(p) };
|
let pointer = unsafe { <P as NonNullPtr>::from_raw(p) };
|
||||||
// It is OK not to delay the drop because the RCU primitive is
|
// It is OK not to delay the drop because the RCU primitive is
|
||||||
// owned by nobody else.
|
// owned by nobody else.
|
||||||
drop(pointer);
|
drop(pointer);
|
||||||
@ -204,16 +194,23 @@ impl<P: OwnerPtr> Drop for RcuInner<P> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// The inner implementation of both [`RcuReadGuard`] and [`RcuOptionReadGuard`].
|
/// The inner implementation of both [`RcuReadGuard`] and [`RcuOptionReadGuard`].
|
||||||
struct RcuReadGuardInner<'a, P: OwnerPtr> {
|
struct RcuReadGuardInner<'a, P: NonNullPtr> {
|
||||||
obj_ptr: *mut <P as OwnerPtr>::Target,
|
obj_ptr: *mut <P as NonNullPtr>::Target,
|
||||||
rcu: &'a RcuInner<P>,
|
rcu: &'a RcuInner<P>,
|
||||||
_inner_guard: DisabledPreemptGuard,
|
_inner_guard: DisabledPreemptGuard,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<P: OwnerPtr> RcuReadGuardInner<'_, P> {
|
impl<P: NonNullPtr> RcuReadGuardInner<'_, P> {
|
||||||
|
fn get(&self) -> Option<P::Ref<'_>> {
|
||||||
|
// SAFETY: The guard ensures that `P` will not be dropped. Thus, `P`
|
||||||
|
// outlives the lifetime of `&self`. Additionally, during this period,
|
||||||
|
// it is impossible to create a mutable reference to `P`.
|
||||||
|
NonNull::new(self.obj_ptr).map(|ptr| unsafe { P::raw_as_ref(ptr) })
|
||||||
|
}
|
||||||
|
|
||||||
fn compare_exchange(self, new_ptr: Option<P>) -> Result<(), Option<P>> {
|
fn compare_exchange(self, new_ptr: Option<P>) -> Result<(), Option<P>> {
|
||||||
let new_ptr = if let Some(new_ptr) = new_ptr {
|
let new_ptr = if let Some(new_ptr) = new_ptr {
|
||||||
<P as OwnerPtr>::into_raw(new_ptr).as_ptr()
|
<P as NonNullPtr>::into_raw(new_ptr).as_ptr()
|
||||||
} else {
|
} else {
|
||||||
core::ptr::null_mut()
|
core::ptr::null_mut()
|
||||||
};
|
};
|
||||||
@ -231,7 +228,7 @@ impl<P: OwnerPtr> RcuReadGuardInner<'_, P> {
|
|||||||
// 1. It was previously returned by `into_raw`.
|
// 1. It was previously returned by `into_raw`.
|
||||||
// 2. The `compare_exchange` fails so the pointer will not
|
// 2. The `compare_exchange` fails so the pointer will not
|
||||||
// be used by other threads via reading the RCU primitive.
|
// be used by other threads via reading the RCU primitive.
|
||||||
return Err(Some(unsafe { <P as OwnerPtr>::from_raw(new_ptr) }));
|
return Err(Some(unsafe { <P as NonNullPtr>::from_raw(new_ptr) }));
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(p) = NonNull::new(self.obj_ptr) {
|
if let Some(p) = NonNull::new(self.obj_ptr) {
|
||||||
@ -243,7 +240,7 @@ impl<P: OwnerPtr> RcuReadGuardInner<'_, P> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<P: OwnerPtr> Rcu<P> {
|
impl<P: NonNullPtr> Rcu<P> {
|
||||||
/// Creates a new RCU primitive with the given pointer.
|
/// Creates a new RCU primitive with the given pointer.
|
||||||
pub fn new(pointer: P) -> Self {
|
pub fn new(pointer: P) -> Self {
|
||||||
Self(RcuInner::new(pointer))
|
Self(RcuInner::new(pointer))
|
||||||
@ -279,15 +276,12 @@ impl<P: OwnerPtr> Rcu<P> {
|
|||||||
/// Unlike [`Self::read`], this function does not return a read guard, so
|
/// Unlike [`Self::read`], this function does not return a read guard, so
|
||||||
/// you cannot use [`RcuReadGuard::compare_exchange`] to synchronize the
|
/// you cannot use [`RcuReadGuard::compare_exchange`] to synchronize the
|
||||||
/// writers. You may do it via a [`super::SpinLock`].
|
/// writers. You may do it via a [`super::SpinLock`].
|
||||||
pub fn read_with<'a>(
|
pub fn read_with<'a>(&'a self, guard: &'a dyn AsAtomicModeGuard) -> P::Ref<'a> {
|
||||||
&'a self,
|
|
||||||
guard: &'a dyn AsAtomicModeGuard,
|
|
||||||
) -> &'a <P as OwnerPtr>::Target {
|
|
||||||
self.0.read_with(guard).unwrap()
|
self.0.read_with(guard).unwrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<P: OwnerPtr> RcuOption<P> {
|
impl<P: NonNullPtr> RcuOption<P> {
|
||||||
/// Creates a new RCU primitive with the given pointer.
|
/// Creates a new RCU primitive with the given pointer.
|
||||||
pub fn new(pointer: Option<P>) -> Self {
|
pub fn new(pointer: Option<P>) -> Self {
|
||||||
if let Some(pointer) = pointer {
|
if let Some(pointer) = pointer {
|
||||||
@ -337,29 +331,17 @@ impl<P: OwnerPtr> RcuOption<P> {
|
|||||||
/// Unlike [`Self::read`], this function does not return a read guard, so
|
/// Unlike [`Self::read`], this function does not return a read guard, so
|
||||||
/// you cannot use [`RcuOptionReadGuard::compare_exchange`] to synchronize the
|
/// you cannot use [`RcuOptionReadGuard::compare_exchange`] to synchronize the
|
||||||
/// writers. You may do it via a [`super::SpinLock`].
|
/// writers. You may do it via a [`super::SpinLock`].
|
||||||
pub fn read_with<'a>(
|
pub fn read_with<'a>(&'a self, guard: &'a dyn AsAtomicModeGuard) -> Option<P::Ref<'a>> {
|
||||||
&'a self,
|
|
||||||
guard: &'a dyn AsAtomicModeGuard,
|
|
||||||
) -> Option<&'a <P as OwnerPtr>::Target> {
|
|
||||||
self.0.read_with(guard)
|
self.0.read_with(guard)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// RCU guards that have a non-null pointer can be directly dereferenced.
|
impl<P: NonNullPtr> RcuReadGuard<'_, P> {
|
||||||
impl<P: OwnerPtr> Deref for RcuReadGuard<'_, P> {
|
/// Gets the reference of the protected data.
|
||||||
type Target = <P as OwnerPtr>::Target;
|
pub fn get(&self) -> P::Ref<'_> {
|
||||||
|
self.0.get().unwrap()
|
||||||
fn deref(&self) -> &Self::Target {
|
|
||||||
// SAFETY:
|
|
||||||
// 1. This pointer is not NULL because the type is `RcuReadGuard`.
|
|
||||||
// 2. Since the preemption is disabled, the pointer is valid because
|
|
||||||
// other writers won't release the allocation until this task passes
|
|
||||||
// the quiescent state.
|
|
||||||
unsafe { &*self.0.obj_ptr }
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl<P: OwnerPtr> RcuReadGuard<'_, P> {
|
|
||||||
/// Tries to replace the already read pointer with a new pointer.
|
/// Tries to replace the already read pointer with a new pointer.
|
||||||
///
|
///
|
||||||
/// If another thread has updated the pointer after the read, this
|
/// If another thread has updated the pointer after the read, this
|
||||||
@ -380,21 +362,12 @@ impl<P: OwnerPtr> RcuReadGuard<'_, P> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// RCU guards that may have a null pointer can be dereferenced after checking.
|
impl<P: NonNullPtr> RcuOptionReadGuard<'_, P> {
|
||||||
impl<P: OwnerPtr> RcuOptionReadGuard<'_, P> {
|
|
||||||
/// Gets the reference of the protected data.
|
/// Gets the reference of the protected data.
|
||||||
///
|
///
|
||||||
/// If the RCU primitive protects nothing, this function returns `None`.
|
/// If the RCU primitive protects nothing, this function returns `None`.
|
||||||
pub fn get(&self) -> Option<&<P as OwnerPtr>::Target> {
|
pub fn get(&self) -> Option<P::Ref<'_>> {
|
||||||
if self.0.obj_ptr.is_null() {
|
self.0.get()
|
||||||
return None;
|
|
||||||
}
|
|
||||||
// SAFETY:
|
|
||||||
// 1. This pointer is not NULL.
|
|
||||||
// 2. Since the preemption is disabled, the pointer is valid because
|
|
||||||
// other writers won't release the allocation until this task passes
|
|
||||||
// the quiescent state.
|
|
||||||
Some(unsafe { &*self.0.obj_ptr })
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns if the RCU primitive protects nothing when [`Rcu::read`] happens.
|
/// Returns if the RCU primitive protects nothing when [`Rcu::read`] happens.
|
||||||
@ -425,12 +398,12 @@ impl<P: OwnerPtr> RcuOptionReadGuard<'_, P> {
|
|||||||
///
|
///
|
||||||
/// The pointer must be previously returned by `into_raw` and the pointer
|
/// The pointer must be previously returned by `into_raw` and the pointer
|
||||||
/// must be only be dropped once.
|
/// must be only be dropped once.
|
||||||
unsafe fn delay_drop<P: OwnerPtr>(pointer: NonNull<<P as OwnerPtr>::Target>) {
|
unsafe fn delay_drop<P: NonNullPtr>(pointer: NonNull<<P as NonNullPtr>::Target>) {
|
||||||
struct ForceSend<P: OwnerPtr>(NonNull<<P as OwnerPtr>::Target>);
|
struct ForceSend<P: NonNullPtr>(NonNull<<P as NonNullPtr>::Target>);
|
||||||
// SAFETY: Sending a raw pointer to another task is safe as long as
|
// SAFETY: Sending a raw pointer to another task is safe as long as
|
||||||
// the pointer access in another task is safe (guaranteed by the trait
|
// the pointer access in another task is safe (guaranteed by the trait
|
||||||
// bound `P: Send`).
|
// bound `P: Send`).
|
||||||
unsafe impl<P: OwnerPtr> Send for ForceSend<P> {}
|
unsafe impl<P: NonNullPtr> Send for ForceSend<P> {}
|
||||||
|
|
||||||
let pointer: ForceSend<P> = ForceSend(pointer);
|
let pointer: ForceSend<P> = ForceSend(pointer);
|
||||||
|
|
||||||
@ -444,7 +417,7 @@ unsafe fn delay_drop<P: OwnerPtr>(pointer: NonNull<<P as OwnerPtr>::Target>) {
|
|||||||
// 1. The pointer was previously returned by `into_raw`.
|
// 1. The pointer was previously returned by `into_raw`.
|
||||||
// 2. The pointer won't be used anymore since the grace period has
|
// 2. The pointer won't be used anymore since the grace period has
|
||||||
// finished and this is the only time the pointer gets dropped.
|
// finished and this is the only time the pointer gets dropped.
|
||||||
let p = unsafe { <P as OwnerPtr>::from_raw(pointer.0) };
|
let p = unsafe { <P as NonNullPtr>::from_raw(pointer.0) };
|
||||||
drop(p);
|
drop(p);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
190
ostd/src/sync/rcu/non_null.rs
Normal file
190
ostd/src/sync/rcu/non_null.rs
Normal file
@ -0,0 +1,190 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
//! This module provides a trait and some auxiliary types to help abstract and
|
||||||
|
//! work with non-null pointers.
|
||||||
|
|
||||||
|
use core::{marker::PhantomData, mem::ManuallyDrop, ops::Deref, ptr::NonNull};
|
||||||
|
|
||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
/// A trait that abstracts non-null pointers.
|
||||||
|
///
|
||||||
|
/// All common smart pointer types such as `Box<T>`, `Arc<T>`, and `Weak<T>`
|
||||||
|
/// implement this trait as they can be converted to and from the raw pointer
|
||||||
|
/// type of `*const T`.
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// This trait must be implemented correctly (according to the doc comments for
|
||||||
|
/// each method). Types like [`Rcu`] rely on this assumption to safely use the
|
||||||
|
/// raw pointers.
|
||||||
|
///
|
||||||
|
/// [`Rcu`]: super::Rcu
|
||||||
|
pub unsafe trait NonNullPtr: Send + 'static {
|
||||||
|
/// The target type that this pointer refers to.
|
||||||
|
// TODO: Support `Target: ?Sized`.
|
||||||
|
type Target;
|
||||||
|
|
||||||
|
/// A type that behaves just like a shared reference to the `NonNullPtr`.
|
||||||
|
type Ref<'a>: Deref<Target = Self>
|
||||||
|
where
|
||||||
|
Self: 'a;
|
||||||
|
|
||||||
|
/// Converts to a raw pointer.
|
||||||
|
///
|
||||||
|
/// Each call to `into_raw` must be paired with a call to `from_raw`
|
||||||
|
/// in order to avoid memory leakage.
|
||||||
|
fn into_raw(self) -> NonNull<Self::Target>;
|
||||||
|
|
||||||
|
/// Converts back from a raw pointer.
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// 1. The raw pointer must have been previously returned by a call to
|
||||||
|
/// `into_raw`.
|
||||||
|
/// 2. The raw pointer must not be used after calling `from_raw`.
|
||||||
|
///
|
||||||
|
/// Note that the second point is a hard requirement: Even if the
|
||||||
|
/// resulting value has not (yet) been dropped, the pointer cannot be
|
||||||
|
/// used because it may break Rust aliasing rules (e.g., `Box<T>`
|
||||||
|
/// requires the pointer to be unique and thus _never_ aliased).
|
||||||
|
unsafe fn from_raw(ptr: NonNull<Self::Target>) -> Self;
|
||||||
|
|
||||||
|
/// Obtains a shared reference to the original pointer.
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// The original pointer must outlive the lifetime parameter `'a`, and during `'a`
|
||||||
|
/// no mutable references to the pointer will exist.
|
||||||
|
unsafe fn raw_as_ref<'a>(raw: NonNull<Self::Target>) -> Self::Ref<'a>;
|
||||||
|
|
||||||
|
/// Converts a shared reference to a raw pointer.
|
||||||
|
fn ref_as_raw(ptr_ref: Self::Ref<'_>) -> NonNull<Self::Target>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A type that represents `&'a Box<T>`.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct BoxRef<'a, T> {
|
||||||
|
inner: *mut T,
|
||||||
|
_marker: PhantomData<&'a T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Deref for BoxRef<'_, T> {
|
||||||
|
type Target = Box<T>;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
// SAFETY: A `Box<T>` is guaranteed to be represented by a single pointer [1] and a shared
|
||||||
|
// reference to the `Box<T>` during the lifetime `'a` can be created according to the
|
||||||
|
// safety requirements of `NonNullPtr::raw_as_ref`.
|
||||||
|
//
|
||||||
|
// [1]: https://doc.rust-lang.org/std/boxed/#memory-layout
|
||||||
|
unsafe { core::mem::transmute(&self.inner) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T> BoxRef<'a, T> {
|
||||||
|
/// Dereferences `self` to get a reference to `T` with the lifetime `'a`.
|
||||||
|
pub fn deref_target(&self) -> &'a T {
|
||||||
|
// SAFETY: The reference is created through `NonNullPtr::raw_as_ref`, hence
|
||||||
|
// the original owned pointer and target must outlive the lifetime parameter `'a`,
|
||||||
|
// and during `'a` no mutable references to the pointer will exist.
|
||||||
|
unsafe { &*(self.inner) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl<T: Send + 'static> NonNullPtr for Box<T> {
|
||||||
|
type Target = T;
|
||||||
|
|
||||||
|
type Ref<'a>
|
||||||
|
= BoxRef<'a, T>
|
||||||
|
where
|
||||||
|
Self: 'a;
|
||||||
|
|
||||||
|
fn into_raw(self) -> NonNull<Self::Target> {
|
||||||
|
let ptr = Box::into_raw(self);
|
||||||
|
|
||||||
|
// SAFETY: The pointer representing a `Box` can never be NULL.
|
||||||
|
unsafe { NonNull::new_unchecked(ptr) }
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn from_raw(ptr: NonNull<Self::Target>) -> Self {
|
||||||
|
let ptr = ptr.as_ptr();
|
||||||
|
|
||||||
|
// SAFETY: The safety is upheld by the caller.
|
||||||
|
unsafe { Box::from_raw(ptr) }
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn raw_as_ref<'a>(raw: NonNull<Self::Target>) -> Self::Ref<'a> {
|
||||||
|
BoxRef {
|
||||||
|
inner: raw.as_ptr(),
|
||||||
|
_marker: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ref_as_raw(ptr_ref: Self::Ref<'_>) -> NonNull<Self::Target> {
|
||||||
|
// SAFETY: The pointer representing a `Box` can never be NULL.
|
||||||
|
unsafe { NonNull::new_unchecked(ptr_ref.inner) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A type that represents `&'a Arc<T>`.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct ArcRef<'a, T> {
|
||||||
|
inner: ManuallyDrop<Arc<T>>,
|
||||||
|
_marker: PhantomData<&'a Arc<T>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Deref for ArcRef<'_, T> {
|
||||||
|
type Target = Arc<T>;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.inner
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T> ArcRef<'a, T> {
|
||||||
|
/// Dereferences `self` to get a reference to `T` with the lifetime `'a`.
|
||||||
|
pub fn deref_target(&self) -> &'a T {
|
||||||
|
// SAFETY: The reference is created through `NonNullPtr::raw_as_ref`, hence
|
||||||
|
// the original owned pointer and target must outlive the lifetime parameter `'a`,
|
||||||
|
// and during `'a` no mutable references to the pointer will exist.
|
||||||
|
unsafe { &*(self.deref().deref() as *const T) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl<T: Send + Sync + 'static> NonNullPtr for Arc<T> {
|
||||||
|
type Target = T;
|
||||||
|
|
||||||
|
type Ref<'a>
|
||||||
|
= ArcRef<'a, T>
|
||||||
|
where
|
||||||
|
Self: 'a;
|
||||||
|
|
||||||
|
fn into_raw(self) -> NonNull<Self::Target> {
|
||||||
|
let ptr = Arc::into_raw(self).cast_mut();
|
||||||
|
|
||||||
|
// SAFETY: The pointer representing an `Arc` can never be NULL.
|
||||||
|
unsafe { NonNull::new_unchecked(ptr) }
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn from_raw(ptr: NonNull<Self::Target>) -> Self {
|
||||||
|
let ptr = ptr.as_ptr().cast_const();
|
||||||
|
|
||||||
|
// SAFETY: The safety is upheld by the caller.
|
||||||
|
unsafe { Arc::from_raw(ptr) }
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn raw_as_ref<'a>(raw: NonNull<Self::Target>) -> Self::Ref<'a> {
|
||||||
|
// SAFETY: The safety is upheld by the caller.
|
||||||
|
unsafe {
|
||||||
|
ArcRef {
|
||||||
|
inner: ManuallyDrop::new(Arc::from_raw(raw.as_ptr())),
|
||||||
|
_marker: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ref_as_raw(ptr_ref: Self::Ref<'_>) -> NonNull<Self::Target> {
|
||||||
|
NonNullPtr::into_raw(ManuallyDrop::into_inner(ptr_ref.inner))
|
||||||
|
}
|
||||||
|
}
|
@ -1,94 +0,0 @@
|
|||||||
// SPDX-License-Identifier: MPL-2.0
|
|
||||||
|
|
||||||
use core::ptr::NonNull;
|
|
||||||
|
|
||||||
use crate::prelude::*;
|
|
||||||
|
|
||||||
/// A trait that abstracts pointers that have the ownership of the objects they
|
|
||||||
/// refer to.
|
|
||||||
///
|
|
||||||
/// The most typical examples smart pointer types like `Box<T>` and `Arc<T>`,
|
|
||||||
/// which can be converted to and from the raw pointer type of `*const T`.
|
|
||||||
///
|
|
||||||
/// # Safety
|
|
||||||
///
|
|
||||||
/// This trait must be implemented correctly (according to the doc comments for
|
|
||||||
/// each method). Types like [`Rcu`] rely on this assumption to safely use the
|
|
||||||
/// raw pointers.
|
|
||||||
///
|
|
||||||
/// [`Rcu`]: super::Rcu
|
|
||||||
pub unsafe trait OwnerPtr: Send + 'static {
|
|
||||||
/// The target type that this pointer refers to.
|
|
||||||
// TODO: allow ?Sized
|
|
||||||
type Target;
|
|
||||||
|
|
||||||
/// Creates a new pointer with the given value.
|
|
||||||
fn new(value: Self::Target) -> Self;
|
|
||||||
|
|
||||||
/// Converts to a raw pointer.
|
|
||||||
///
|
|
||||||
/// Each call to `into_raw` must be paired with a call to `from_raw`
|
|
||||||
/// in order to avoid memory leakage.
|
|
||||||
///
|
|
||||||
/// The resulting raw pointer must be valid to be immutably accessed
|
|
||||||
/// or borrowed until `from_raw` is called.
|
|
||||||
fn into_raw(self) -> NonNull<Self::Target>;
|
|
||||||
|
|
||||||
/// Converts back from a raw pointer.
|
|
||||||
///
|
|
||||||
/// # Safety
|
|
||||||
///
|
|
||||||
/// 1. The raw pointer must have been previously returned by a call to
|
|
||||||
/// `into_raw`.
|
|
||||||
/// 2. The raw pointer must not be used after calling `from_raw`.
|
|
||||||
///
|
|
||||||
/// Note that the second point is a hard requirement: Even if the
|
|
||||||
/// resulting value has not (yet) been dropped, the pointer cannot be
|
|
||||||
/// used because it may break Rust aliasing rules (e.g., `Box<T>`
|
|
||||||
/// requires the pointer to be unique and thus _never_ aliased).
|
|
||||||
unsafe fn from_raw(ptr: NonNull<Self::Target>) -> Self;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl<T: Send + 'static> OwnerPtr for Box<T> {
|
|
||||||
type Target = T;
|
|
||||||
|
|
||||||
fn new(value: Self::Target) -> Self {
|
|
||||||
Box::new(value)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn into_raw(self) -> NonNull<Self::Target> {
|
|
||||||
let ptr = Box::into_raw(self);
|
|
||||||
|
|
||||||
// SAFETY: The pointer representing a `Box` can never be NULL.
|
|
||||||
unsafe { NonNull::new_unchecked(ptr) }
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn from_raw(ptr: NonNull<Self::Target>) -> Self {
|
|
||||||
let ptr = ptr.as_ptr();
|
|
||||||
|
|
||||||
// SAFETY: The safety is upheld by the caller.
|
|
||||||
unsafe { Box::from_raw(ptr) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl<T: Send + Sync + 'static> OwnerPtr for Arc<T> {
|
|
||||||
type Target = T;
|
|
||||||
|
|
||||||
fn new(value: Self::Target) -> Self {
|
|
||||||
Arc::new(value)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn into_raw(self) -> NonNull<Self::Target> {
|
|
||||||
let ptr = Arc::into_raw(self).cast_mut();
|
|
||||||
|
|
||||||
// SAFETY: The pointer representing an `Arc` can never be NULL.
|
|
||||||
unsafe { NonNull::new_unchecked(ptr) }
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn from_raw(ptr: NonNull<Self::Target>) -> Self {
|
|
||||||
let ptr = ptr.as_ptr().cast_const();
|
|
||||||
|
|
||||||
// SAFETY: The safety is upheld by the caller.
|
|
||||||
unsafe { Arc::from_raw(ptr) }
|
|
||||||
}
|
|
||||||
}
|
|
Reference in New Issue
Block a user