1use core::alloc::{GlobalAlloc, Layout};
5
6use hermit_sync::RawInterruptTicketMutex;
7use talc::{ErrOnOom, Span, Talc, Talck};
8
9pub struct LockedAllocator(Talck<RawInterruptTicketMutex, ErrOnOom>);
10
11impl LockedAllocator {
12 pub const fn new() -> Self {
13 Self(Talc::new(ErrOnOom).lock())
14 }
15
16 #[inline]
17 fn align_layout(layout: Layout) -> Layout {
18 let align = layout
19 .align()
20 .max(core::mem::align_of::<crossbeam_utils::CachePadded<u8>>());
21 Layout::from_size_align(layout.size(), align).unwrap()
22 }
23
24 pub unsafe fn init(&self, heap_bottom: *mut u8, heap_size: usize) {
25 let arena = Span::from_base_size(heap_bottom, heap_size);
26 unsafe {
27 self.0.lock().claim(arena).unwrap();
28 }
29 }
30}
31
32unsafe impl GlobalAlloc for LockedAllocator {
35 unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
36 let layout = Self::align_layout(layout);
37 unsafe { self.0.alloc(layout) }
38 }
39
40 unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
41 let layout = Self::align_layout(layout);
42 unsafe { self.0.dealloc(ptr, layout) }
43 }
44
45 unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
46 let layout = Self::align_layout(layout);
47 unsafe { self.0.alloc_zeroed(layout) }
48 }
49
50 unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
51 let layout = Self::align_layout(layout);
52 unsafe { self.0.realloc(ptr, layout, new_size) }
53 }
54}
55
56#[cfg(all(test, not(target_os = "none")))]
57mod tests {
58 use core::mem;
59
60 use super::*;
61
62 #[test]
63 fn empty() {
64 const ARENA_SIZE: usize = 0x1000;
65 let mut arena: [u8; ARENA_SIZE] = [0; ARENA_SIZE];
66 let allocator: LockedAllocator = LockedAllocator::new();
67 unsafe {
68 allocator.init(arena.as_mut_ptr(), ARENA_SIZE);
69 }
70
71 let layout = Layout::from_size_align(1, 1).unwrap();
72 assert!(unsafe { !allocator.alloc(layout.clone()).is_null() });
74
75 let layout = Layout::from_size_align(0x1000, mem::align_of::<usize>()).unwrap();
76 let addr = unsafe { allocator.alloc(layout) };
77 assert!(addr.is_null());
78 }
79}