Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 18 additions & 1 deletion src/structs/shared_buffer/internal/owned.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,18 @@ use crate::structs::shared_buffer::internal::vtable::Vtable;
///
/// Enables SharedBuffer to manage any container implementing AsRef<[u8]>
/// with atomic reference counting for safe sharing.
///
/// The `drop_fn` field stores a type-erased destructor so that
/// `owned_drop` can properly clean up the concrete `Owned<T>` without
/// knowing T at the vtable level.
#[repr(C)]
pub(crate) struct Owned<T: AsRef<[u8]> + Send + Sync + 'static> {
pub(crate) ref_cnt: AtomicUsize,
pub(crate) drop_fn: unsafe fn(*mut ()),
pub(crate) owner: T,
}


/// Clones owned buffer by incrementing reference count.
unsafe fn owned_clone(h: &AtomicPtr<()>, p: *const u8, l: usize) -> SharedBuffer {
let raw = h.load(Ordering::Acquire);
Expand All @@ -43,14 +49,25 @@ unsafe fn owned_clone(h: &AtomicPtr<()>, p: *const u8, l: usize) -> SharedBuffer
}

/// Decrements reference count, deallocating if last reference.
///
/// Reads the type-erased destructor stored in the `Owned` header
/// to properly drop the concrete `Owned<T>` and run T's destructor.
unsafe fn owned_drop(h: &mut AtomicPtr<()>, _p: *const u8, _l: usize) {
let raw = h.load(Ordering::Acquire);
if raw.is_null() {
return;
}
let ref_cnt = unsafe { &*(raw as *const AtomicUsize) };
if ref_cnt.fetch_sub(1, Ordering::AcqRel) == 1 {
drop(unsafe { Box::from_raw(raw) });
// Read the drop function stored after ref_cnt in the Owned header.
// This is safe because Owned is #[repr(C)] with ref_cnt first,
// drop_fn second - the layout is the same for all Owned<T>.
let drop_fn_ptr = unsafe {
(raw as *const u8).add(std::mem::size_of::<AtomicUsize>())
as *const unsafe fn(*mut ())
};
let drop_fn = unsafe { *drop_fn_ptr };
drop_fn(raw);
}
}

Expand Down
4 changes: 4 additions & 0 deletions src/structs/shared_buffer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -154,8 +154,12 @@ impl SharedBuffer {
where
T: AsRef<[u8]> + Send + Sync + 'static,
{
unsafe fn drop_typed<T: AsRef<[u8]> + Send + Sync + 'static>(ptr: *mut ()) {
unsafe { drop(Box::from_raw(ptr as *mut Owned<T>)); }
}
let raw: *mut Owned<T> = Box::into_raw(Box::new(Owned {
ref_cnt: AtomicUsize::new(1),
drop_fn: drop_typed::<T>,
owner,
}));
let buf = unsafe { (*raw).owner.as_ref() };
Expand Down
Loading