use crate::local_alloc::ThreadAllocator;
use mnemosyne_arena::HasSegmentPool;
use mnemosyne_core::constants::{PAGE_SIZE, PAGES_PER_SEGMENT};
#[cfg(test)]
use mnemosyne_core::policy::AllocPolicy;
use mnemosyne_core::types::{Segment, SegmentOwner};
#[inline(always)]
pub(crate) unsafe fn push_owned_segment_front_raw(
raw_segment: *mut Segment,
head_slot: &mut *mut Segment,
) {
unsafe {
(*raw_segment).prev_owned_segment = core::ptr::null_mut();
(*raw_segment).next_owned_segment = *head_slot;
if !(*head_slot).is_null() {
(**head_slot).prev_owned_segment = raw_segment;
}
*head_slot = raw_segment;
}
}
#[inline(always)]
pub(crate) unsafe fn unlink_owned_segment_from_list_raw(
raw_segment: *mut Segment,
head_slot: &mut *mut Segment,
) {
unsafe {
let prev = (*raw_segment).prev_owned_segment;
let next = (*raw_segment).next_owned_segment;
if prev.is_null() {
*head_slot = next;
} else {
(*prev).next_owned_segment = next;
}
if !next.is_null() {
(*next).prev_owned_segment = prev;
}
(*raw_segment).prev_owned_segment = core::ptr::null_mut();
(*raw_segment).next_owned_segment = core::ptr::null_mut();
}
}
impl<B: HasSegmentPool> ThreadAllocator<B> {
#[inline(always)]
unsafe fn push_owned_segment_core(&mut self, segment: *mut Segment) {
let allocator_ptr = (self as *mut ThreadAllocator<B>).cast::<core::ffi::c_void>();
unsafe { Segment::set_owner_allocator(segment, allocator_ptr) };
#[cfg(all(windows, target_arch = "x86_64", not(miri)))]
unsafe {
Segment::set_owner(
segment,
SegmentOwner::from_thread_id(mnemosyne_core::types::current_thread_id()),
)
};
#[cfg(not(all(windows, target_arch = "x86_64", not(miri))))]
unsafe {
Segment::set_owner(
segment,
SegmentOwner::from_ptr(self as *mut ThreadAllocator<B>),
)
};
unsafe { push_owned_segment_front_raw(segment, &mut self.owned_segments_head) };
self.owned_segment_count += 1;
}
#[cfg(test)]
#[inline]
pub(crate) unsafe fn push_owned_segment<P: AllocPolicy>(&mut self, segment: *mut Segment) {
unsafe { self.push_owned_segment_dynamic(segment, P::ENABLE_FREE_LIST_ENCRYPTION) }
}
#[inline]
pub(crate) unsafe fn push_owned_segment_dynamic(
&mut self,
segment: *mut Segment,
enable_encryption: bool,
) {
unsafe { self.push_owned_segment_core(segment) };
if enable_encryption {
let already_keyed = unsafe { (*segment).free_list_encrypted };
if !already_keyed {
unsafe { self.initialize_segment_keys(segment) };
}
}
}
#[inline]
pub unsafe fn initialize_segment_keys(&mut self, segment: *mut Segment) {
let seed = super::super::get_tls_seed();
let process_key = super::super::get_process_key();
let segment_addr = segment as usize;
unsafe {
(*segment).free_list_encrypted = true;
for i in 0..PAGES_PER_SEGMENT {
(*segment).keys[i] =
(segment_addr.wrapping_add(i * PAGE_SIZE)) ^ seed ^ process_key;
}
}
}
#[inline]
pub(crate) unsafe fn unlink_owned_segment(&mut self, segment: *mut Segment) {
unsafe { unlink_owned_segment_from_list_raw(segment, &mut self.owned_segments_head) };
debug_assert!(self.owned_segment_count > 0);
self.owned_segment_count -= 1;
}
}