use core::ffi::c_void;
use core::ptr::NonNull;
use mnemosyne_core::types::{Block, Page, Segment, SegmentOwner};
#[inline(always)]
pub(crate) unsafe fn is_sole_active_page(
active_head: Option<NonNull<Page>>,
page: *const Page,
) -> bool {
active_head.is_some_and(|head| {
core::ptr::eq(head.as_ptr(), page) && unsafe { (*head.as_ptr()).next_page.is_none() }
})
}
#[inline(always)]
pub(crate) unsafe fn commit_in_place_free(
block: *mut Block,
page: *mut Page,
_page_free: Option<NonNull<Block>>,
cookie: usize,
encrypted: bool,
page_alloc_count: usize,
randomized: bool,
) {
unsafe {
let (current_head, use_secondary) =
Page::choose_free_head(page, page_alloc_count, randomized);
(*block).set_next_dynamic(current_head, encrypted, cookie);
if use_secondary {
(*page).secondary_free = Some(NonNull::new_unchecked(block));
} else {
(*page).free = Some(NonNull::new_unchecked(block));
}
(*page).alloc_count = (page_alloc_count - 1) as u32;
}
}
#[inline]
pub(crate) unsafe fn resolve_owner_slot(
#[cfg_attr(
not(all(windows, target_arch = "x86_64", not(miri))),
expect(
unused_variables,
reason = "only the Windows x86-64 owner path reads the segment header"
)
)]
segment: *mut Segment,
owner: SegmentOwner,
slot_ptr: *mut c_void,
) -> (bool, *mut c_void) {
#[cfg(all(windows, target_arch = "x86_64", not(miri)))]
{
let tid = mnemosyne_core::types::current_thread_id();
let owner_allocator = unsafe { Segment::owner_allocator(segment) };
let same_thread_owner = !owner_allocator.is_null() && owner.matches_thread_id(tid);
let caller_owner = !slot_ptr.is_null() && owner.matches(slot_ptr);
if same_thread_owner {
return (true, owner_allocator);
}
if caller_owner {
return (true, slot_ptr);
}
(false, core::ptr::null_mut())
}
#[cfg(not(all(windows, target_arch = "x86_64", not(miri))))]
{
let caller_owner = !slot_ptr.is_null() && owner.matches(slot_ptr);
if caller_owner {
(true, slot_ptr)
} else {
(false, core::ptr::null_mut())
}
}
}
#[inline(always)]
pub unsafe fn free_large_or_huge_raw<B: mnemosyne_arena::HasSegmentPool>(
ptr: *mut u8,
enable_poisoning: bool,
poison_free_byte: u8,
) {
let segment = unsafe { *((ptr as *mut *mut Segment).sub(1)) };
if enable_poisoning {
let size = unsafe { (*segment).huge_mapping_suffix_from(ptr) };
unsafe { core::ptr::write_bytes(ptr, poison_free_byte, size) };
}
let _ = unsafe { mnemosyne_arena::deallocate_large_or_huge::<B>(ptr, segment) };
}