Skip to main content

relibc/platform/allocator/
mod.rs

1use 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}