Created
January 10, 2024 22:36
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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