more memory allocation stuff

This commit is contained in:
Heikki Linnakangas
2025-05-02 02:13:45 +03:00
parent e40193e3c8
commit 54cd2272f1
12 changed files with 485 additions and 174 deletions

View File

@@ -5,12 +5,14 @@ use std::sync::atomic::{AtomicU64, Ordering};
use spin;
const BLOCK_SIZE: usize = 16*1024;
use crate::allocator::r#static::StaticAllocator;
const BLOCK_SIZE: usize = 16 * 1024;
const INVALID_BLOCK: u64 = u64::MAX;
pub(crate) struct BlockAllocator {
blocks_ptr: *mut MaybeUninit<u8>,
pub(crate) struct BlockAllocator<'t> {
blocks_ptr: &'t [MaybeUninit<u8>],
num_blocks: u64,
num_initialized: AtomicU64,
@@ -28,23 +30,19 @@ struct FreeListBlockInner {
free_blocks: [u64; 100], // FIXME: fill the rest of the block
}
impl<'t> BlockAllocator<'t> {
pub(crate) fn new(area: &'t mut [MaybeUninit<u8>]) -> Self {
let mut alloc = StaticAllocator::new(area);
impl BlockAllocator {
pub(crate) fn new(ptr: *mut MaybeUninit<u8>, size: usize) -> Self {
let mut p = ptr;
// Use all the space for the blocks
let padding = p.align_offset(BLOCK_SIZE);
p = unsafe { p.byte_add(padding) };
let blocks_ptr = p;
alloc.align(BLOCK_SIZE);
let used = unsafe { p.byte_offset_from(ptr) as usize };
assert!(used <= size);
let blocks_size = size - used;
let remain = alloc.remaining();
let num_blocks = (blocks_size / BLOCK_SIZE) as u64;
let num_blocks = (remain.len() / BLOCK_SIZE) as u64;
BlockAllocator {
blocks_ptr,
blocks_ptr: remain,
num_blocks,
num_initialized: AtomicU64::new(0),
freelist_head: spin::Mutex::new(INVALID_BLOCK),
@@ -60,7 +58,13 @@ impl BlockAllocator {
fn get_block_ptr(&self, blkno: u64) -> *mut u8 {
assert!(blkno < self.num_blocks);
unsafe { self.blocks_ptr.byte_offset(blkno as isize * BLOCK_SIZE as isize) }.cast()
unsafe {
self.blocks_ptr
.as_ptr()
.byte_offset(blkno as isize * BLOCK_SIZE as isize)
}
.cast_mut()
.cast()
}
pub(crate) fn alloc_block(&self) -> *mut u8 {
@@ -95,14 +99,19 @@ impl BlockAllocator {
// If there are some blocks left that we've never used, pick next such block
let mut next_uninitialized = self.num_initialized.load(Ordering::Relaxed);
while next_uninitialized < self.num_blocks {
match self.num_initialized.compare_exchange(next_uninitialized, next_uninitialized + 1, Ordering::Relaxed, Ordering::Relaxed) {
match self.num_initialized.compare_exchange(
next_uninitialized,
next_uninitialized + 1,
Ordering::Relaxed,
Ordering::Relaxed,
) {
Ok(_) => {
return next_uninitialized;
},
}
Err(old) => {
next_uninitialized = old;
continue;
},
}
}
}

View File

@@ -0,0 +1,56 @@
use std::alloc::Layout;
use std::mem::MaybeUninit;
use crate::allocator::block::BlockAllocator;
use crate::allocator::slab::SlabDesc;
use crate::allocator::r#static::StaticAllocator;
pub struct MultiSlabAllocator<'t, const N: usize> {
pub(crate) block_allocator: BlockAllocator<'t>,
pub(crate) slab_descs: [SlabDesc; N],
}
unsafe impl<'t, const N: usize> Sync for MultiSlabAllocator<'t, N> {}
unsafe impl<'t, const N: usize> Send for MultiSlabAllocator<'t, N> {}
impl<'t, const N: usize> MultiSlabAllocator<'t, N> {
pub(crate) fn new(
area: &'t mut [MaybeUninit<u8>],
layouts: &[Layout; N],
) -> &'t mut MultiSlabAllocator<'t, N> {
// Set up the MultiSlabAllocator struct in the area first
let mut allocator = StaticAllocator::new(area);
let this = allocator.alloc_uninit();
let block_allocator = BlockAllocator::new(allocator.remaining());
let this = this.write(MultiSlabAllocator {
block_allocator,
slab_descs: std::array::from_fn(|i| SlabDesc::new(&layouts[i])),
});
this
}
pub(crate) fn alloc_fit(&self, layout: Layout) -> *mut u8 {
for i in 0..self.slab_descs.len() {
if self.slab_descs[i].layout.align() >= layout.align()
&& self.slab_descs[i].layout.size() >= layout.size()
{
return self.alloc_slab(i);
}
}
panic!("no suitable slab found for allocation");
}
pub(crate) fn alloc_slab(&self, slab_idx: usize) -> *mut u8 {
self.slab_descs[slab_idx].alloc_chunk(&self.block_allocator)
}
pub(crate) fn dealloc_slab(&self, slab_idx: usize, ptr: *mut u8) {
self.slab_descs[slab_idx].dealloc_chunk(ptr, &self.block_allocator)
}
}

View File

@@ -0,0 +1,57 @@
use std::mem::MaybeUninit;
pub struct StaticAllocator<'t> {
area: &'t mut [MaybeUninit<u8>],
}
impl<'t> StaticAllocator<'t> {
pub fn new(_area: &'t mut [MaybeUninit<u8>]) -> StaticAllocator<'t> {
todo!()
}
/*
pub fn alloc<T>(&mut self, _init: T) -> &'t T {
todo!()
}
*/
pub fn alloc_uninit<T>(&mut self) -> &'t mut MaybeUninit<T> {
todo!()
}
pub fn remaining(self) -> &'t mut [MaybeUninit<u8>] {
self.area
}
pub fn align(&mut self, _alignment: usize) {
todo!()
}
/*
pub fn static_alloc<'a, T: Sized>(&'a self, value: T) -> AllocatedBox<'a, T> {
let sz = std::mem::size_of::<T>();
// pad all allocations to MAXALIGN boundaries
assert!(std::mem::align_of::<T>() <= MAXALIGN);
let sz = sz.next_multiple_of(MAXALIGN);
let offset = self.allocated.fetch_add(sz, Ordering::Relaxed);
if offset + sz > self.size {
panic!("out of memory");
}
let inner = unsafe {
let inner = self.area.offset(offset as isize).cast::<T>();
*inner = value;
NonNull::new_unchecked(inner)
};
AllocatedBox {
inner,
_phantom: PhantomData,
}
}
*/
}