baby_mimalloc/
lib.rs

1/*
2 * Copyright 2024 Yufan You
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17//! [Mimalloc](https://github.com/microsoft/mimalloc) implemented in Rust
18//! (not a binding to the C library) with only basic features.
19//!
20//! Lock-free multi-threading, security features, and some performance enhancements are not
21//! implemented.
22//!
23//! It can be used in `no_std` environments.
24//!
25//! # Crate Features
26//!
27//! - **mmap** - Provide [`MimallocMmap`] that uses `mmap` as OS allocator for segments.
28//! - **std_mutex** - Provide [`MimallocMutexWrapper`] that wraps [`Mimalloc`] inside
29//!   [`std::sync::Mutex`] and implements [`GlobalAlloc`].
30//! - **spin_mutex** - Provide [`MimallocMutexWrapper`] that wraps [`Mimalloc`] inside
31//!   [`spin::Mutex`] that can be used in `no_std` environments.
32//! - **deferred_free** - Enable registering a hook to complete deferred free events.
33//!   See the documentation of [`mi_register_deferred_free`](https://microsoft.github.io/mimalloc/group__extended.html#ga3460a6ca91af97be4058f523d3cb8ece).
34
35#![cfg_attr(docsrs, feature(doc_auto_cfg))]
36#![cfg_attr(not(feature = "std"), no_std)]
37
38mod constants;
39mod heap;
40mod list;
41mod page;
42mod segment;
43mod utils;
44
45use core::alloc::{GlobalAlloc, Layout};
46use heap::Heap;
47
48/* wrapper around `heap::Heap` to defined the public API. */
49
50/// The main allocator object.
51///
52/// `A` is the type of the OS allocator for segments.
53///
54/// To use it as the [`global_allocator`], wrap it inside a lock and implement [`GlobalAlloc`].
55/// See [`MimallocMutexWrapper`].
56#[derive(Default)]
57pub struct Mimalloc<A: GlobalAlloc> {
58    heap: Heap,
59    os_alloc: A,
60    #[cfg(feature = "deferred_free")]
61    deferred_free_hook: Option<DeferredFreeHook<A>>,
62}
63
64#[cfg(feature = "deferred_free")]
65pub mod deferred_free;
66#[cfg(feature = "deferred_free")]
67use deferred_free::*;
68
69unsafe impl<A: GlobalAlloc> Send for Mimalloc<A> {}
70
71impl<A: GlobalAlloc> Mimalloc<A> {
72    /// Create a new [`Mimalloc`] instance with an OS allocator.
73    pub const fn with_os_allocator(os_alloc: A) -> Self {
74        Self {
75            heap: Heap::new(),
76            os_alloc,
77            #[cfg(feature = "deferred_free")]
78            deferred_free_hook: None,
79        }
80    }
81
82    #[cfg(feature = "deferred_free")]
83    /// Register a hook to complete deferred free when the allocator needs more memory.
84    /// A new hook replaces the old one.
85    ///
86    /// See the documentation of
87    /// [`mi_register_deferred_free`](https://microsoft.github.io/mimalloc/group__extended.html#ga3460a6ca91af97be4058f523d3cb8ece)
88    /// (the extra `arg` is not supported).
89    pub const fn register_deferred_free(&mut self, hook: DeferredFreeHook<A>) {
90        self.deferred_free_hook = Some(hook);
91    }
92
93    /// Collect free memory.
94    pub fn collect(&mut self) {
95        self.heap.collect(&self.os_alloc);
96    }
97
98    /// [`GlobalAlloc::alloc`] but requires a mutable reference `&mut self`.
99    ///
100    /// # Safety
101    ///
102    /// See [`GlobalAlloc::alloc`].
103    pub unsafe fn alloc(&mut self, layout: Layout) -> *mut u8 {
104        self.heap.malloc_aligned(
105            layout.size(),
106            layout.align(),
107            &self.os_alloc,
108            #[cfg(feature = "deferred_free")]
109            self.deferred_free_hook,
110        )
111    }
112
113    /// [`GlobalAlloc::dealloc`] but requires a mutable reference `&mut self`.
114    ///
115    /// # Safety
116    ///
117    /// See [`GlobalAlloc::dealloc`].
118    pub unsafe fn dealloc(&mut self, ptr: *mut u8, _: Layout) {
119        self.heap.free(ptr, &self.os_alloc)
120    }
121}
122
123impl<A: GlobalAlloc> Drop for Mimalloc<A> {
124    fn drop(&mut self) {
125        self.collect();
126    }
127}
128
129#[cfg(feature = "mmap")]
130mod mmap;
131#[cfg(feature = "mmap")]
132pub use mmap::{new_mimalloc_mmap, MimallocMmap, MmapAlloc};
133
134#[cfg(all(not(docsrs), feature = "std_mutex", feature = "spin_mutex"))]
135compile_error!("Only one of 'std_mutex' and 'spin_mutex' features can be enabled");
136
137#[cfg(any(feature = "std_mutex", feature = "spin_mutex"))]
138mod mutex;
139#[cfg(any(feature = "std_mutex", feature = "spin_mutex"))]
140pub use mutex::MimallocMutexWrapper;
141
142#[cfg(all(feature = "mmap", any(feature = "std_mutex", feature = "spin_mutex")))]
143/// Wrapper around [`Mimalloc`] with `mmap` allocator and mutex.
144pub type MimallocMmapMutex = MimallocMutexWrapper<MmapAlloc>;
145#[cfg(all(feature = "mmap", any(feature = "std_mutex", feature = "spin_mutex")))]
146/// Create a new [`MimallocMmapMutex`] instance by a `const fn`.
147pub const fn new_mimalloc_mmap_mutex() -> MimallocMmapMutex {
148    MimallocMutexWrapper::with_os_allocator(MmapAlloc)
149}