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