Enable RCU to read reference to stored pointers

This commit is contained in:
Chen Chengjun
2025-04-10 10:32:17 +08:00
committed by Tate, Hongliang Tian
parent 36f6f9bcd4
commit a21e895102
6 changed files with 244 additions and 181 deletions

View File

@ -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);

View File

@ -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;
} }
} }

View File

@ -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,

View File

@ -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);
}); });
} }

View 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))
}
}

View File

@ -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) }
}
}