1use crate::raw::{NonNullSlice, Optional};
2
3use super::syscalls;
4use core::{cell::UnsafeCell, ptr::NonNull};
5
6#[derive(Debug, Default)]
7struct Block {
8 free: bool,
9 next: Option<NonNull<Block>>,
10 data_len: usize,
11}
12
13impl Block {
14 pub fn create(data_len: usize) -> Option<NonNull<Self>> {
16 let size = data_len + size_of::<Block>();
17 let size = size.next_multiple_of(align_of::<Block>());
18 assert!(size <= isize::MAX as usize);
19
20 let ptr = get_data_break() as *mut Block;
21 syscalls::sbrk(size as isize).ok()?;
22 unsafe {
23 *ptr = Self {
24 free: true,
25 data_len: size - size_of::<Block>(),
26 ..Default::default()
27 };
28 Some(NonNull::new_unchecked(ptr))
29 }
30 }
31
32 #[inline(always)]
33 pub unsafe fn block_from_data_ptr(data: NonNull<u8>) -> NonNull<Self> {
36 unsafe { NonNull::new_unchecked((data.as_ptr() as *mut Block).offset(-1)) }
37 }
38
39 #[inline(always)]
40 pub unsafe fn data_from_ptr(ptr: *const Self) -> NonNull<[u8]> {
42 unsafe {
43 let length = (*ptr).data_len;
44 let ptr_to_data = ptr.offset(1) as *const u8 as *mut u8;
45 NonNull::new_unchecked(core::slice::from_raw_parts_mut(ptr_to_data, length) as *mut [u8])
46 }
47 }
48}
49
50pub struct SystemAllocator {
51 head: Option<NonNull<Block>>,
52}
53
54fn get_data_break() -> *mut u8 {
55 unsafe { syscalls::sbrk(0).unwrap_unchecked() }
57}
58
59impl SystemAllocator {
60 const fn new() -> Self {
61 Self { head: None }
62 }
63
64 #[inline]
66 fn try_find_block(&self, data_len: usize) -> Option<NonNull<Block>> {
67 let size = data_len + size_of::<Block>();
69 let size = size.next_multiple_of(align_of::<Block>());
70 let data_len = size - size_of::<Block>();
71
72 let mut current = self.head;
73 let mut best_block: Option<(NonNull<Block>, usize)> = None;
74
75 while let Some(block_ptr) = current {
76 let block = unsafe { &*block_ptr.as_ptr() };
77 if !block.free {
78 current = block.next;
79 continue;
80 }
81
82 if block.data_len == data_len {
83 return Some(block_ptr);
84 }
85
86 if block.data_len > data_len
87 && best_block.is_none_or(|(_, bb_len)| bb_len > block.data_len)
88 {
89 best_block = Some((block_ptr, block.data_len));
90 }
91
92 current = block.next;
93 }
94
95 best_block.map(|(ptr, _)| ptr)
96 }
97
98 #[inline]
101 fn find_block(&mut self, data_len: usize) -> Option<NonNull<Block>> {
102 if let Some(block) = self.try_find_block(data_len) {
103 Some(block)
104 } else {
105 unsafe {
106 let new_block = Block::create(data_len)?;
107 let stolen_head = self.head.take();
108
109 (*new_block.as_ptr()).next = stolen_head;
110 self.head = Some(new_block);
111
112 Some(new_block)
113 }
114 }
115 }
116
117 fn allocate(&mut self, size: usize) -> Option<NonNull<[u8]>> {
118 let block = self.find_block(size)?;
119 unsafe {
120 let ptr = block.as_ptr();
121 (*ptr).free = false;
122 Some(Block::data_from_ptr(ptr))
123 }
124 }
125
126 unsafe fn deallocate(&mut self, block_data: NonNull<u8>) {
127 unsafe {
128 let block_ptr = Block::block_from_data_ptr(block_data).as_ptr();
129 let block = &mut *block_ptr;
130 block.free = true;
131 }
132 }
133}
134
135unsafe impl Send for SystemAllocator {}
136unsafe impl Sync for SystemAllocator {}
137
138pub struct GlobalSystemAllocator {
140 inner: UnsafeCell<SystemAllocator>,
141}
142
143impl GlobalSystemAllocator {
144 const fn new() -> Self {
145 Self {
146 inner: UnsafeCell::new(SystemAllocator::new()),
147 }
148 }
149 #[inline]
150 pub fn allocate(&self, size: usize) -> Option<NonNull<[u8]>> {
151 unsafe { (*self.inner.get()).allocate(size) }
152 }
153 #[inline]
154 pub unsafe fn deallocate(&self, ptr: NonNull<u8>) {
155 unsafe { (*self.inner.get()).deallocate(ptr) }
156 }
157
158 }
160
161unsafe impl Sync for GlobalSystemAllocator {}
162unsafe impl Send for GlobalSystemAllocator {}
163
164pub static GLOBAL_SYSTEM_ALLOCATOR: GlobalSystemAllocator = GlobalSystemAllocator::new();
165
166#[cfg(not(any(feature = "std", feature = "rustc-dep-of-std")))]
167#[unsafe(no_mangle)]
168extern "C" fn syscreate(object_size: usize) -> Optional<NonNullSlice<u8>> {
170 GLOBAL_SYSTEM_ALLOCATOR
171 .allocate(object_size)
172 .map(|mut x| unsafe {
173 let x = x.as_mut();
174 let len = x.len();
175 let ptr = NonNull::new_unchecked(x.as_mut_ptr());
176 NonNullSlice::from_raw_parts(ptr, len)
177 })
178 .into()
179}
180
181#[cfg(not(any(feature = "std", feature = "rustc-dep-of-std")))]
182#[unsafe(no_mangle)]
183unsafe extern "C" fn sysdestroy(object_ptr: *mut u8) {
184 unsafe {
185 match NonNull::new(object_ptr) {
186 Some(ptr) => GLOBAL_SYSTEM_ALLOCATOR.deallocate(ptr),
187 None => (),
188 }
189 }
190}