Skip to content

Instantly share code, notes, and snippets.

@BurntNail
Created January 10, 2024 22:36
Show Gist options
  • Save BurntNail/ec64fb3c2ec3bfcb94d38ecfe9b39b2c to your computer and use it in GitHub Desktop.
Save BurntNail/ec64fb3c2ec3bfcb94d38ecfe9b39b2c to your computer and use it in GitHub Desktop.
Allocator that only deals with 4-4 layouts, and only has 64 slots for concurrent allocations
use std::sync::atomic::{AtomicBool, Ordering::SeqCst};
use std::cell::UnsafeCell;
use std::alloc::{GlobalAlloc, Layout};
pub struct FourAllocator {
is_allocating: AtomicBool,
tracker: UnsafeCell<usize>,
spaces: UnsafeCell<[u8; usize::BITS as usize * 4]>
}
unsafe impl Sync for FourAllocator {}
unsafe impl GlobalAlloc for FourAllocator {
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
if layout.size() != 4 || layout.align() != 4 {
return std::ptr::null_mut();
}
//wait until we can start allocating
while self.is_allocating.compare_exchange(false, true, SeqCst, SeqCst).is_err() {std::thread::yield_now()}
//theoretically, now only this thread should be able to allocate
let tracker_ptr = self.tracker.get();
let tracker_copied: usize = *tracker_ptr;
//Sound, as we're the only thread accessing this pointer
let mut chosen_index = None;
for i in 0..usize::BITS {
if tracker_copied & (1 << i) == 0 {
*tracker_ptr = tracker_copied | (1 << i);
chosen_index = Some(i as usize);
break;
}
}
//we're done with the tracker, so we can give back our lock
self.is_allocating.store(false, SeqCst);
let Some(chosen_index) = chosen_index else {
return std::ptr::null_mut();
};
(self.spaces.get() as *mut u8).add(chosen_index * 4)
}
unsafe fn dealloc (&self, ptr: *mut u8, _layout: Layout) {
let offset = (ptr as usize - self.spaces.get() as usize) / 4;
while self.is_allocating.compare_exchange(false, true, SeqCst, SeqCst).is_err() {std::thread::yield_now()}
let ptr = self.tracker.get();
*ptr = *ptr - (1 << offset);
self.is_allocating.store(false, SeqCst);
}
}
static ALLOCATOR: FourAllocator = FourAllocator {
tracker: UnsafeCell::new(0),
is_allocating: AtomicBool::new(false),
spaces: UnsafeCell::new([0; usize::BITS as usize * 4])
};
fn main () {
let layout = Layout::new::<u32>();
let mut to_be_freed = Vec::with_capacity(10);
for i in 0..16 {
let ptr = unsafe {ALLOCATOR.alloc(layout)};
println!("{ptr:?}");
if ptr.is_null() {
println!("What?");
}
to_be_freed.push(ptr);
if i % 5 == 0 {
for ptr in std::mem::take(&mut to_be_freed) {
unsafe { ALLOCATOR.dealloc(ptr, layout) };
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment