Skip to content

Commit ffe2e0e

Browse files
wedsonafintel-lab-lkp
authored andcommitted
rust: sync: add Arc::{from_raw, into_raw}
These methods can be used to turn an `Arc` into a raw pointer and back, in a way that preserves the metadata for fat pointers. This is done using the unstable ptr_metadata feature [1]. However, it could also be done using the unstable pointer_byte_offsets feature [2], which is likely to have a shorter path to stabilization than ptr_metadata. Link: rust-lang/rust#81513 [1] Link: rust-lang/rust#96283 [2] Signed-off-by: Wedson Almeida Filho <walmeida@microsoft.com> Co-developed-by: Alice Ryhl <aliceryhl@google.com> Signed-off-by: Alice Ryhl <aliceryhl@google.com>
1 parent ab4cb07 commit ffe2e0e

File tree

2 files changed

+45
-0
lines changed

2 files changed

+45
-0
lines changed

rust/kernel/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#![feature(generic_associated_types)]
2323
#![feature(new_uninit)]
2424
#![feature(pin_macro)]
25+
#![feature(ptr_metadata)]
2526
#![feature(receiver_trait)]
2627
#![feature(unsize)]
2728

rust/kernel/sync/arc.rs

+44
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,50 @@ impl<T: ?Sized> Arc<T> {
210210
}
211211
}
212212

213+
/// Convert the [`Arc`] into a raw pointer.
214+
///
215+
/// The raw pointer has ownership of the refcount that this Arc object owned.
216+
pub fn into_raw(self) -> *const T {
217+
let ptr = self.ptr.as_ptr();
218+
core::mem::forget(self);
219+
// SAFETY: The pointer is valid.
220+
unsafe { core::ptr::addr_of!((*ptr).data) }
221+
}
222+
223+
/// Recreates an [`Arc`] instance previously deconstructed via [`Arc::into_raw`].
224+
///
225+
/// This code relies on the `repr(C)` layout of structs as described in
226+
/// <https://doc.rust-lang.org/reference/type-layout.html#reprc-structs>.
227+
///
228+
/// # Safety
229+
///
230+
/// `ptr` must have been returned by a previous call to [`Arc::into_raw`]. Additionally, it
231+
/// can only be called once for each previous call to [`Arc::into_raw`].
232+
pub unsafe fn from_raw(ptr: *const T) -> Self {
233+
// SAFETY: The safety requirement ensures that the pointer is valid.
234+
let val_align = core::mem::align_of_val(unsafe { &*ptr });
235+
let refcount_size = core::mem::size_of::<Opaque<bindings::refcount_t>>();
236+
237+
// Use the `repr(C)` algorithm to compute the offset of `data` in `ArcInner`.
238+
//
239+
// Pseudo-code for the `#[repr(C)]` algorithm can be found here:
240+
// <https://doc.rust-lang.org/reference/type-layout.html#reprc-structs>
241+
let mut val_offset = refcount_size;
242+
let val_misalign = val_offset % val_align;
243+
if val_misalign > 0 {
244+
val_offset += val_align - val_misalign;
245+
}
246+
247+
// This preserves the metadata in the pointer, if any.
248+
let metadata = core::ptr::metadata(ptr as *const ArcInner<T>);
249+
let ptr = (ptr as *mut u8).wrapping_sub(val_offset) as *mut ();
250+
let ptr = core::ptr::from_raw_parts_mut(ptr, metadata);
251+
252+
// SAFETY: By the safety requirements we know that `ptr` came from `Arc::into_raw`, so the
253+
// reference count held then will be owned by the new `Arc` object.
254+
unsafe { Self::from_inner(NonNull::new_unchecked(ptr)) }
255+
}
256+
213257
/// Returns an [`ArcBorrow`] from the given [`Arc`].
214258
///
215259
/// This is useful when the argument of a function call is an [`ArcBorrow`] (e.g., in a method

0 commit comments

Comments
 (0)