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