relibc/platform/allocator/
mod.rs1use core::{
2 alloc::{GlobalAlloc, Layout},
3 cell::SyncUnsafeCell,
4 cmp,
5 mem::align_of,
6 ptr::{self, copy_nonoverlapping, write_bytes},
7 sync::atomic::{AtomicPtr, Ordering},
8};
9
10mod sys;
11use super::types::*;
12use crate::{ALLOCATOR, sync::Mutex};
13use dlmalloc::DlmallocCApi;
14
15pub type Dlmalloc = DlmallocCApi<sys::System>;
16
17#[allow(clippy::declare_interior_mutable_const)]
18pub const NEWALLOCATOR: Allocator = Allocator::new();
19
20pub struct Allocator {
21 inner: SyncUnsafeCell<Mutex<Dlmalloc>>,
22 pub ptr: AtomicPtr<Mutex<Dlmalloc>>,
23}
24
25impl Allocator {
26 #[allow(clippy::new_without_default)]
27 pub const fn new() -> Self {
28 Allocator {
29 inner: SyncUnsafeCell::new(Mutex::new(Dlmalloc::new(sys::System::new()))),
30 ptr: AtomicPtr::new(ptr::null_mut()),
31 }
32 }
33
34 pub fn get(&self) -> *const Mutex<Dlmalloc> {
35 let ptr = self.ptr.load(Ordering::Acquire);
36 if !ptr.is_null() {
37 return ptr;
38 }
39
40 self.inner.get()
41 }
42
43 pub fn set(&self, mspace: *const Mutex<Dlmalloc>) {
44 self.ptr.store(mspace.cast_mut(), Ordering::Release);
45 }
46}
47
48unsafe impl GlobalAlloc for Allocator {
49 #[inline]
50 unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
51 if layout.align() <= align_of::<max_align_t>() {
52 unsafe { (*self.get()).lock().malloc(layout.size()) }
53 } else {
54 unsafe { (*self.get()).lock().memalign(layout.align(), layout.size()) }
55 }
56 }
57
58 #[inline]
59 unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
60 unsafe { (*self.get()).lock().free(ptr) }
61 }
62
63 #[inline]
64 unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
65 let ptr = unsafe { self.alloc(layout) };
66 if !ptr.is_null() && unsafe { (*self.get()).lock().calloc_must_clear(ptr) } {
67 unsafe { write_bytes(ptr, 0, layout.size()) };
68 }
69 ptr
70 }
71
72 #[inline]
73 unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
74 if layout.align() <= align_of::<max_align_t>() {
75 unsafe { (*self.get()).lock().realloc(ptr, new_size) }
76 } else {
77 let new =
78 unsafe { self.alloc(Layout::from_size_align_unchecked(new_size, layout.align())) };
79 let old_size = layout.size();
80
81 if !new.is_null() {
82 let size = cmp::min(old_size, new_size);
83 unsafe { copy_nonoverlapping(ptr, new, size) };
84 }
85
86 unsafe { (*self.get()).lock().free(ptr) };
87
88 new
89 }
90 }
91}
92
93pub unsafe fn alloc(size: size_t) -> *mut c_void {
94 unsafe { (*ALLOCATOR.get()).lock().malloc(size) }.cast()
95}
96
97pub unsafe fn alloc_align(size: size_t, alignment: size_t) -> *mut c_void {
98 unsafe { (*ALLOCATOR.get()).lock().memalign(alignment, size) }.cast()
99}
100
101pub unsafe fn realloc(ptr: *mut c_void, size: size_t) -> *mut c_void {
102 if ptr.is_null() {
103 unsafe { (*ALLOCATOR.get()).lock().malloc(size) }.cast()
104 } else {
105 unsafe { (*ALLOCATOR.get()).lock().realloc(ptr.cast(), size) }.cast()
106 }
107}
108
109pub unsafe fn free(ptr: *mut c_void) {
110 if ptr.is_null() {
111 return;
112 }
113 unsafe { (*ALLOCATOR.get()).lock().free(ptr.cast()) }
114}
115
116pub unsafe fn alloc_usable_size(ptr: *mut c_void) -> size_t {
117 if ptr.is_null() {
118 return 0;
119 }
120 unsafe { (*ALLOCATOR.get()).lock().usable_size(ptr.cast()) }
121}