Initial commit

This commit is contained in:
2024-03-13 13:00:08 +01:00
commit 536fb4cac3
8 changed files with 363 additions and 0 deletions

150
src/allocator.rs Normal file
View File

@@ -0,0 +1,150 @@
use std::{
mem::size_of,
ptr::NonNull,
sync::{LazyLock, Mutex},
};
use crate::bump_allocator::{BUMP_ALLOCATOR, MEMFD_INITIAL_SIZE};
const ALIGNMENT: usize = 8;
const INITIAL_HEAP_SIZE: usize = MEMFD_INITIAL_SIZE;
const METADATA_SIZE: usize = size_of::<Metadata>();
pub(crate) static ALLOCATOR: LazyLock<Mutex<Allocator>> =
LazyLock::new(|| unsafe { Mutex::new(Allocator::new()) });
struct Metadata {
chunk: NonNull<Chunk>,
}
struct Chunk {
buffer: *mut u8,
size: usize,
in_use: bool,
next_chunk: Option<NonNull<Chunk>>,
prev_chunk: Option<NonNull<Chunk>>,
}
pub(crate) struct Allocator {
head: NonNull<Chunk>,
tail: NonNull<Chunk>,
}
unsafe impl Send for Chunk {}
unsafe impl Send for Allocator {}
impl Allocator {
unsafe fn new() -> Self {
let mut allocator = BUMP_ALLOCATOR.lock().unwrap();
let mem = allocator.alloc(INITIAL_HEAP_SIZE).unwrap();
let head = Box::new(Chunk {
buffer: mem.byte_add(METADATA_SIZE),
size: INITIAL_HEAP_SIZE,
in_use: false,
next_chunk: None,
prev_chunk: None,
});
let head = NonNull::new(Box::leak(head)).unwrap();
let mem = mem as *mut Metadata;
*mem = Metadata { chunk: head };
Allocator { head, tail: head }
}
pub(crate) unsafe fn allocate(&mut self, size: usize) -> Option<*mut u8> {
let size = (size + ALIGNMENT - 1) / ALIGNMENT * ALIGNMENT;
let mut head = Some(self.head);
while head.is_some() {
let current_head = head.unwrap().as_mut();
if !current_head.in_use && current_head.size >= size {
if current_head.size == size {
current_head.in_use = true;
return Some(current_head.buffer);
}
let unused_space = Box::new(Chunk {
buffer: current_head.buffer.byte_add(size + METADATA_SIZE),
size: current_head.size - size - METADATA_SIZE,
in_use: false,
next_chunk: current_head.next_chunk,
prev_chunk: head,
});
let ptr = NonNull::new(Box::leak(unused_space)).unwrap();
*(ptr.as_ref().buffer.byte_sub(METADATA_SIZE) as *mut Metadata) =
Metadata { chunk: ptr };
if ptr.as_ref().next_chunk.is_none() {
self.tail = ptr;
}
current_head.in_use = true;
current_head.size = size;
current_head.next_chunk = Some(ptr);
return Some(current_head.buffer);
}
head = current_head.next_chunk;
}
// TODO: Try to allocate more space from bump allocator
None
}
pub(crate) unsafe fn deallocate(&mut self, ptr: *mut u8) {
let metadata = ptr.byte_sub(METADATA_SIZE) as *mut Metadata;
let metadata = (*metadata).chunk.as_mut();
debug_assert_eq!(metadata.in_use, true);
debug_assert_eq!(metadata.buffer, ptr);
metadata.in_use = false;
// TODO: Consolidate chunks
}
}
#[cfg(test)]
mod tests {
extern crate test;
use core::slice;
use test::Bencher;
use super::ALLOCATOR;
#[test]
fn functionality() {
let mut allocator = ALLOCATOR.lock().unwrap();
unsafe {
let x = allocator.allocate(10).unwrap();
let x = slice::from_raw_parts_mut(x, 10);
x[0] = 1;
assert_eq!(x[0], 1);
allocator.deallocate(x.as_mut_ptr());
}
}
#[bench]
fn allocator_bench(b: &mut Bencher) {
let mut allocator = ALLOCATOR.lock().unwrap();
b.iter(|| unsafe {
let x = allocator.allocate(1).unwrap();
let x = slice::from_raw_parts_mut(x, 1);
x[0] = 1;
assert_eq!(x[0], 1);
allocator.deallocate(x.as_mut_ptr());
});
}
}