Skip to main content

rustfs_mimalloc_sys/
lib.rs

1//! Low-level FFI bindings to [mimalloc](https://github.com/microsoft/mimalloc) V3 (v3.5.1).
2//!
3//! For a safe wrapper, use the `rustfs-mimalloc` crate.
4
5#![no_std]
6#![allow(non_camel_case_types)]
7
8// ── Type aliases ────────────────────────────────────────────────────────────
9
10pub use core::ffi::{c_char, c_int, c_long, c_void};
11
12pub type size_t = usize;
13
14// ── Constants ──────────────────────────────────────────────────────────────
15
16/// Maximum word count for mimalloc's small allocation fast path.
17pub const MI_SMALL_WSIZE_MAX: size_t = 128;
18
19/// Maximum byte size for mimalloc's small allocation fast path.
20pub const MI_SMALL_SIZE_MAX: size_t = MI_SMALL_WSIZE_MAX * core::mem::size_of::<*mut c_void>();
21
22// ── Opaque types ────────────────────────────────────────────────────────────
23
24#[repr(C)]
25pub struct mi_heap_t {
26    _opaque: [u8; 0],
27}
28
29#[repr(C)]
30pub struct mi_theap_t {
31    _opaque: [u8; 0],
32}
33
34/// Subprocess identifier. Opaque handle — do not access fields directly.
35#[repr(C)]
36#[derive(Clone, Copy)]
37pub struct mi_subproc_id_t {
38    _id: *mut c_void,
39}
40
41/// Arena identifier. Opaque handle.
42pub type mi_arena_id_t = *mut c_void;
43
44// ── Option enum ─────────────────────────────────────────────────────────────
45//
46// Kept in sync with mimalloc V3.5.1 `mi_option_e` in `mimalloc.h`.
47
48#[repr(C)]
49#[derive(Debug, Clone, Copy, PartialEq, Eq)]
50pub enum mi_option_t {
51    mi_option_show_errors = 0,
52    mi_option_show_stats = 1,
53    mi_option_verbose = 2,
54    mi_option_arena_eager_commit = 4,
55    mi_option_purge_decommits = 5,
56    mi_option_allow_large_os_pages = 6,
57    mi_option_reserve_huge_os_pages = 7,
58    mi_option_reserve_huge_os_pages_at = 8,
59    mi_option_reserve_os_memory = 9,
60    mi_option_purge_delay = 15,
61    mi_option_use_numa_nodes = 16,
62    mi_option_disallow_os_alloc = 17,
63    mi_option_os_tag = 18,
64    mi_option_max_errors = 19,
65    mi_option_max_warnings = 20,
66    mi_option_destroy_on_exit = 22,
67    mi_option_arena_reserve = 23,
68    mi_option_arena_purge_mult = 24,
69    mi_option_disallow_arena_alloc = 26,
70    mi_option_retry_on_oom = 27,
71    mi_option_guarded_min = 29,
72    mi_option_guarded_max = 30,
73    mi_option_guarded_precise = 31,
74    mi_option_guarded_sample_rate = 32,
75    mi_option_guarded_sample_seed = 33,
76    mi_option_generic_collect = 34,
77    mi_option_page_reclaim_on_free = 35,
78    mi_option_page_full_retain = 36,
79    mi_option_page_max_candidates = 37,
80    mi_option_max_vabits = 38,
81    mi_option_pagemap_commit = 39,
82    mi_option_page_commit_on_demand = 40,
83    mi_option_page_max_reclaim = 41,
84    mi_option_page_cross_thread_max_reclaim = 42,
85    mi_option_allow_thp = 43,
86    mi_option_minimal_purge_size = 44,
87    mi_option_arena_max_object_size = 45,
88    mi_option_arena_is_numa_local = 46,
89}
90
91// ── Heap area (for visiting blocks) ─────────────────────────────────────────
92
93#[repr(C)]
94pub struct mi_heap_area_t {
95    pub blocks: *mut c_void,
96    pub reserved: size_t,
97    pub committed: size_t,
98    pub used: size_t,
99    pub block_size: size_t,
100    pub full_block_size: size_t,
101    pub reserved1: *mut c_void,
102}
103
104// ── Callback types ──────────────────────────────────────────────────────────
105
106pub type mi_output_fun = unsafe extern "C" fn(msg: *const c_char, arg: *mut c_void);
107pub type mi_error_fun = unsafe extern "C" fn(err: c_int, arg: *mut c_void);
108pub type mi_deferred_free_fun = unsafe extern "C" fn(force: bool, heartbeat: u64, arg: *mut c_void);
109pub type mi_block_visit_fun = unsafe extern "C" fn(
110    heap: *const mi_heap_t,
111    area: *const mi_heap_area_t,
112    block: *mut c_void,
113    block_size: size_t,
114    arg: *mut c_void,
115) -> bool;
116pub type mi_heap_visit_fun = unsafe extern "C" fn(heap: *mut mi_heap_t, arg: *mut c_void) -> bool;
117
118// ── Standard malloc interface ───────────────────────────────────────────────
119
120unsafe extern "C" {
121    pub fn mi_malloc(size: size_t) -> *mut c_void;
122    pub fn mi_calloc(count: size_t, size: size_t) -> *mut c_void;
123    pub fn mi_realloc(p: *mut c_void, newsize: size_t) -> *mut c_void;
124    pub fn mi_free(p: *mut c_void);
125    pub fn mi_strdup(s: *const c_char) -> *mut c_char;
126}
127
128// ── Extended allocation ─────────────────────────────────────────────────────
129
130unsafe extern "C" {
131    pub fn mi_malloc_small(size: size_t) -> *mut c_void;
132    pub fn mi_zalloc_small(size: size_t) -> *mut c_void;
133    pub fn mi_zalloc(size: size_t) -> *mut c_void;
134    pub fn mi_mallocn(count: size_t, size: size_t) -> *mut c_void;
135    pub fn mi_reallocn(p: *mut c_void, count: size_t, size: size_t) -> *mut c_void;
136    pub fn mi_usable_size(p: *const c_void) -> size_t;
137    pub fn mi_good_size(size: size_t) -> size_t;
138    pub fn mi_free_size(p: *mut c_void, size: size_t);
139    pub fn mi_free_small(p: *mut c_void);
140    pub fn mi_free_small_nonnull(p: *mut c_void);
141}
142
143/// Free an allocation when the size is statically known by the caller.
144///
145/// This mirrors mimalloc's inline `mi_free_csize` helper.
146///
147/// # Safety
148///
149/// `p` must be null or a valid mimalloc allocation, and `size` must be the
150/// allocation size used for the corresponding allocation.
151#[inline]
152pub unsafe fn mi_free_csize(p: *mut c_void, size: size_t) {
153    if size <= MI_SMALL_SIZE_MAX {
154        unsafe { mi_free_small(p) };
155    } else {
156        unsafe { mi_free(p) };
157    }
158}
159
160/// Free a non-null allocation when the size is statically known by the caller.
161///
162/// This mirrors mimalloc's inline `mi_free_csize_nonnull` helper.
163///
164/// # Safety
165///
166/// `p` must be a non-null valid mimalloc allocation, and `size` must be the
167/// allocation size used for the corresponding allocation.
168#[inline]
169pub unsafe fn mi_free_csize_nonnull(p: *mut c_void, size: size_t) {
170    if size <= MI_SMALL_SIZE_MAX {
171        unsafe { mi_free_small_nonnull(p) };
172    } else {
173        unsafe { mi_free(p) };
174    }
175}
176
177// ── Aligned allocation ──────────────────────────────────────────────────────
178
179unsafe extern "C" {
180    pub fn mi_malloc_aligned(size: size_t, alignment: size_t) -> *mut c_void;
181    pub fn mi_zalloc_aligned(size: size_t, alignment: size_t) -> *mut c_void;
182    pub fn mi_calloc_aligned(count: size_t, size: size_t, alignment: size_t) -> *mut c_void;
183    pub fn mi_realloc_aligned(p: *mut c_void, newsize: size_t, alignment: size_t) -> *mut c_void;
184}
185
186// ── Process & thread lifecycle ──────────────────────────────────────────────
187
188unsafe extern "C" {
189    pub fn mi_collect(force: bool);
190    pub fn mi_thread_set_in_threadpool();
191    pub fn mi_version() -> c_int;
192    pub fn mi_process_info_print_out(out: Option<mi_output_fun>, arg: *mut c_void);
193    pub fn mi_process_info(
194        elapsed_msecs: *mut size_t,
195        user_msecs: *mut size_t,
196        system_msecs: *mut size_t,
197        current_rss: *mut size_t,
198        peak_rss: *mut size_t,
199        current_commit: *mut size_t,
200        peak_commit: *mut size_t,
201        page_faults: *mut size_t,
202    );
203}
204
205// ── Heaps ───────────────────────────────────────────────────────────────────
206
207unsafe extern "C" {
208    pub fn mi_heap_new() -> *mut mi_heap_t;
209    pub fn mi_heap_delete(heap: *mut mi_heap_t);
210    pub fn mi_heap_destroy(heap: *mut mi_heap_t);
211    pub fn mi_heap_collect(heap: *mut mi_heap_t, force: bool);
212    pub fn mi_heap_main() -> *mut mi_heap_t;
213    pub fn mi_heap_of(p: *const c_void) -> *mut mi_heap_t;
214    pub fn mi_heap_contains(heap: *const mi_heap_t, p: *const c_void) -> bool;
215
216    pub fn mi_heap_malloc(heap: *mut mi_heap_t, size: size_t) -> *mut c_void;
217    pub fn mi_heap_zalloc(heap: *mut mi_heap_t, size: size_t) -> *mut c_void;
218    pub fn mi_heap_calloc(heap: *mut mi_heap_t, count: size_t, size: size_t) -> *mut c_void;
219    pub fn mi_heap_realloc(heap: *mut mi_heap_t, p: *mut c_void, newsize: size_t) -> *mut c_void;
220    pub fn mi_heap_malloc_aligned(
221        heap: *mut mi_heap_t,
222        size: size_t,
223        alignment: size_t,
224    ) -> *mut c_void;
225}
226
227// ── Arena management ────────────────────────────────────────────────────────
228
229unsafe extern "C" {
230    pub fn mi_reserve_os_memory_ex(
231        size: size_t,
232        commit: bool,
233        allow_large: bool,
234        exclusive: bool,
235        arena_id: *mut mi_arena_id_t,
236    ) -> c_int;
237    pub fn mi_manage_os_memory_ex(
238        start: *mut c_void,
239        size: size_t,
240        is_committed: bool,
241        is_pinned: bool,
242        is_zero: bool,
243        numa_node: c_int,
244        exclusive: bool,
245        arena_id: *mut mi_arena_id_t,
246    ) -> bool;
247    pub fn mi_arena_min_alignment() -> size_t;
248    pub fn mi_arena_min_size() -> size_t;
249    pub fn mi_arena_max_object_size() -> size_t;
250    pub fn mi_heap_new_in_arena(arena_id: mi_arena_id_t) -> *mut mi_heap_t;
251}
252
253// ── Options ─────────────────────────────────────────────────────────────────
254
255unsafe extern "C" {
256    pub fn mi_option_is_enabled(option: mi_option_t) -> bool;
257    pub fn mi_option_enable(option: mi_option_t);
258    pub fn mi_option_disable(option: mi_option_t);
259    pub fn mi_option_get(option: mi_option_t) -> c_long;
260    pub fn mi_option_get_size(option: mi_option_t) -> size_t;
261    pub fn mi_option_set(option: mi_option_t, value: c_long);
262}
263
264// ── POSIX-compatible ────────────────────────────────────────────────────────
265
266unsafe extern "C" {
267    pub fn mi_posix_memalign(p: *mut *mut c_void, alignment: size_t, size: size_t) -> c_int;
268    pub fn mi_memalign(alignment: size_t, size: size_t) -> *mut c_void;
269    pub fn mi_malloc_size(p: *const c_void) -> size_t;
270    pub fn mi_malloc_usable_size(p: *const c_void) -> size_t;
271}
272
273// ── Statistics ──────────────────────────────────────────────────────────────
274
275unsafe extern "C" {
276    pub fn mi_stats_get_json(buf_size: size_t, buf: *mut c_char) -> *mut c_char;
277    pub fn mi_stats_print_out(out: Option<mi_output_fun>, arg: *mut c_void);
278    pub fn mi_stats_reset();
279    pub fn mi_heap_stats_get_json(
280        heap: *mut mi_heap_t,
281        buf_size: size_t,
282        buf: *mut c_char,
283    ) -> *mut c_char;
284    pub fn mi_heap_stats_print_out(
285        heap: *mut mi_heap_t,
286        out: Option<mi_output_fun>,
287        arg: *mut c_void,
288    );
289}