1 | /* ---------------------------------------------------------------------------- |
2 | Copyright (c) 2018-2022, Microsoft Research, Daan Leijen |
3 | This is free software; you can redistribute it and/or modify it under the |
4 | terms of the MIT license. A copy of the license can be found in the file |
5 | "LICENSE" at the root of this distribution. |
6 | -----------------------------------------------------------------------------*/ |
7 | #pragma once |
8 | #ifndef MIMALLOC_H |
9 | #define MIMALLOC_H |
10 | |
11 | #define MI_MALLOC_VERSION 207 // major + 2 digits minor |
12 | |
13 | // ------------------------------------------------------ |
14 | // Compiler specific attributes |
15 | // ------------------------------------------------------ |
16 | |
17 | #ifdef __cplusplus |
18 | #if (__cplusplus >= 201103L) || (_MSC_VER > 1900) // C++11 |
19 | #define mi_attr_noexcept noexcept |
20 | #else |
21 | #define mi_attr_noexcept throw() |
22 | #endif |
23 | #else |
24 | #define mi_attr_noexcept |
25 | #endif |
26 | |
27 | #if defined(__cplusplus) && (__cplusplus >= 201703) |
28 | #define mi_decl_nodiscard [[nodiscard]] |
29 | #elif (defined(__GNUC__) && (__GNUC__ >= 4)) || defined(__clang__) // includes clang, icc, and clang-cl |
30 | #define mi_decl_nodiscard __attribute__((warn_unused_result)) |
31 | #elif (_MSC_VER >= 1700) |
32 | #define mi_decl_nodiscard _Check_return_ |
33 | #else |
34 | #define mi_decl_nodiscard |
35 | #endif |
36 | |
37 | #if defined(_MSC_VER) || defined(__MINGW32__) |
38 | #if !defined(MI_SHARED_LIB) |
39 | #define mi_decl_export |
40 | #elif defined(MI_SHARED_LIB_EXPORT) |
41 | #define mi_decl_export __declspec(dllexport) |
42 | #else |
43 | #define mi_decl_export __declspec(dllimport) |
44 | #endif |
45 | #if defined(__MINGW32__) |
46 | #define mi_decl_restrict |
47 | #define mi_attr_malloc __attribute__((malloc)) |
48 | #else |
49 | #if (_MSC_VER >= 1900) && !defined(__EDG__) |
50 | #define mi_decl_restrict __declspec(allocator) __declspec(restrict) |
51 | #else |
52 | #define mi_decl_restrict __declspec(restrict) |
53 | #endif |
54 | #define mi_attr_malloc |
55 | #endif |
56 | #define mi_cdecl __cdecl |
57 | #define mi_attr_alloc_size(s) |
58 | #define mi_attr_alloc_size2(s1,s2) |
59 | #define mi_attr_alloc_align(p) |
60 | #elif defined(__GNUC__) // includes clang and icc |
61 | #if defined(MI_SHARED_LIB) && defined(MI_SHARED_LIB_EXPORT) |
62 | #define mi_decl_export __attribute__((visibility("default"))) |
63 | #else |
64 | #define mi_decl_export |
65 | #endif |
66 | #define mi_cdecl // leads to warnings... __attribute__((cdecl)) |
67 | #define mi_decl_restrict |
68 | #define mi_attr_malloc __attribute__((malloc)) |
69 | #if (defined(__clang_major__) && (__clang_major__ < 4)) || (__GNUC__ < 5) |
70 | #define mi_attr_alloc_size(s) |
71 | #define mi_attr_alloc_size2(s1,s2) |
72 | #define mi_attr_alloc_align(p) |
73 | #elif defined(__INTEL_COMPILER) |
74 | #define mi_attr_alloc_size(s) __attribute__((alloc_size(s))) |
75 | #define mi_attr_alloc_size2(s1,s2) __attribute__((alloc_size(s1,s2))) |
76 | #define mi_attr_alloc_align(p) |
77 | #else |
78 | #define mi_attr_alloc_size(s) __attribute__((alloc_size(s))) |
79 | #define mi_attr_alloc_size2(s1,s2) __attribute__((alloc_size(s1,s2))) |
80 | #define mi_attr_alloc_align(p) __attribute__((alloc_align(p))) |
81 | #endif |
82 | #else |
83 | #define mi_cdecl |
84 | #define mi_decl_export |
85 | #define mi_decl_restrict |
86 | #define mi_attr_malloc |
87 | #define mi_attr_alloc_size(s) |
88 | #define mi_attr_alloc_size2(s1,s2) |
89 | #define mi_attr_alloc_align(p) |
90 | #endif |
91 | |
92 | // ------------------------------------------------------ |
93 | // Includes |
94 | // ------------------------------------------------------ |
95 | |
96 | #include <stddef.h> // size_t |
97 | #include <stdbool.h> // bool |
98 | #include <stdint.h> // INTPTR_MAX |
99 | |
100 | #ifdef __cplusplus |
101 | extern "C" { |
102 | #endif |
103 | |
104 | // ------------------------------------------------------ |
105 | // Standard malloc interface |
106 | // ------------------------------------------------------ |
107 | |
108 | mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_malloc(size_t size) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size(1); |
109 | mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_calloc(size_t count, size_t size) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size2(1,2); |
110 | mi_decl_nodiscard mi_decl_export void* mi_realloc(void* p, size_t newsize) mi_attr_noexcept mi_attr_alloc_size(2); |
111 | mi_decl_export void* mi_expand(void* p, size_t newsize) mi_attr_noexcept mi_attr_alloc_size(2); |
112 | |
113 | mi_decl_export void mi_free(void* p) mi_attr_noexcept; |
114 | mi_decl_nodiscard mi_decl_export mi_decl_restrict char* mi_strdup(const char* s) mi_attr_noexcept mi_attr_malloc; |
115 | mi_decl_nodiscard mi_decl_export mi_decl_restrict char* mi_strndup(const char* s, size_t n) mi_attr_noexcept mi_attr_malloc; |
116 | mi_decl_nodiscard mi_decl_export mi_decl_restrict char* mi_realpath(const char* fname, char* resolved_name) mi_attr_noexcept mi_attr_malloc; |
117 | |
118 | // ------------------------------------------------------ |
119 | // Extended functionality |
120 | // ------------------------------------------------------ |
121 | #define MI_SMALL_WSIZE_MAX (128) |
122 | #define MI_SMALL_SIZE_MAX (MI_SMALL_WSIZE_MAX*sizeof(void*)) |
123 | |
124 | mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_malloc_small(size_t size) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size(1); |
125 | mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_zalloc_small(size_t size) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size(1); |
126 | mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_zalloc(size_t size) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size(1); |
127 | |
128 | mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_mallocn(size_t count, size_t size) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size2(1,2); |
129 | mi_decl_nodiscard mi_decl_export void* mi_reallocn(void* p, size_t count, size_t size) mi_attr_noexcept mi_attr_alloc_size2(2,3); |
130 | mi_decl_nodiscard mi_decl_export void* mi_reallocf(void* p, size_t newsize) mi_attr_noexcept mi_attr_alloc_size(2); |
131 | |
132 | mi_decl_nodiscard mi_decl_export size_t mi_usable_size(const void* p) mi_attr_noexcept; |
133 | mi_decl_nodiscard mi_decl_export size_t mi_good_size(size_t size) mi_attr_noexcept; |
134 | |
135 | |
136 | // ------------------------------------------------------ |
137 | // Internals |
138 | // ------------------------------------------------------ |
139 | |
140 | typedef void (mi_cdecl mi_deferred_free_fun)(bool force, unsigned long long heartbeat, void* arg); |
141 | mi_decl_export void mi_register_deferred_free(mi_deferred_free_fun* deferred_free, void* arg) mi_attr_noexcept; |
142 | |
143 | typedef void (mi_cdecl mi_output_fun)(const char* msg, void* arg); |
144 | mi_decl_export void mi_register_output(mi_output_fun* out, void* arg) mi_attr_noexcept; |
145 | |
146 | typedef void (mi_cdecl mi_error_fun)(int err, void* arg); |
147 | mi_decl_export void mi_register_error(mi_error_fun* fun, void* arg); |
148 | |
149 | mi_decl_export void mi_collect(bool force) mi_attr_noexcept; |
150 | mi_decl_export int mi_version(void) mi_attr_noexcept; |
151 | mi_decl_export void mi_stats_reset(void) mi_attr_noexcept; |
152 | mi_decl_export void mi_stats_merge(void) mi_attr_noexcept; |
153 | mi_decl_export void mi_stats_print(void* out) mi_attr_noexcept; // backward compatibility: `out` is ignored and should be NULL |
154 | mi_decl_export void mi_stats_print_out(mi_output_fun* out, void* arg) mi_attr_noexcept; |
155 | |
156 | mi_decl_export void mi_process_init(void) mi_attr_noexcept; |
157 | mi_decl_export void mi_thread_init(void) mi_attr_noexcept; |
158 | mi_decl_export void mi_thread_done(void) mi_attr_noexcept; |
159 | mi_decl_export void mi_thread_stats_print_out(mi_output_fun* out, void* arg) mi_attr_noexcept; |
160 | |
161 | mi_decl_export void mi_process_info(size_t* elapsed_msecs, size_t* user_msecs, size_t* system_msecs, |
162 | size_t* , size_t* , |
163 | size_t* current_commit, size_t* peak_commit, size_t* page_faults) mi_attr_noexcept; |
164 | |
165 | // ------------------------------------------------------------------------------------- |
166 | // Aligned allocation |
167 | // Note that `alignment` always follows `size` for consistency with unaligned |
168 | // allocation, but unfortunately this differs from `posix_memalign` and `aligned_alloc`. |
169 | // ------------------------------------------------------------------------------------- |
170 | #if (INTPTR_MAX > INT32_MAX) |
171 | #define MI_ALIGNMENT_MAX (16*1024*1024UL) // maximum supported alignment is 16MiB |
172 | #else |
173 | #define MI_ALIGNMENT_MAX (1024*1024UL) // maximum supported alignment for 32-bit systems is 1MiB |
174 | #endif |
175 | |
176 | mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_malloc_aligned(size_t size, size_t alignment) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size(1) mi_attr_alloc_align(2); |
177 | mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_malloc_aligned_at(size_t size, size_t alignment, size_t offset) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size(1); |
178 | mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_zalloc_aligned(size_t size, size_t alignment) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size(1) mi_attr_alloc_align(2); |
179 | mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_zalloc_aligned_at(size_t size, size_t alignment, size_t offset) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size(1); |
180 | mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_calloc_aligned(size_t count, size_t size, size_t alignment) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size2(1,2) mi_attr_alloc_align(3); |
181 | mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_calloc_aligned_at(size_t count, size_t size, size_t alignment, size_t offset) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size2(1,2); |
182 | mi_decl_nodiscard mi_decl_export void* mi_realloc_aligned(void* p, size_t newsize, size_t alignment) mi_attr_noexcept mi_attr_alloc_size(2) mi_attr_alloc_align(3); |
183 | mi_decl_nodiscard mi_decl_export void* mi_realloc_aligned_at(void* p, size_t newsize, size_t alignment, size_t offset) mi_attr_noexcept mi_attr_alloc_size(2); |
184 | |
185 | |
186 | // ------------------------------------------------------------------------------------- |
187 | // Heaps: first-class, but can only allocate from the same thread that created it. |
188 | // ------------------------------------------------------------------------------------- |
189 | |
190 | struct mi_heap_s; |
191 | typedef struct mi_heap_s mi_heap_t; |
192 | |
193 | mi_decl_nodiscard mi_decl_export mi_heap_t* mi_heap_new(void); |
194 | mi_decl_export void mi_heap_delete(mi_heap_t* heap); |
195 | mi_decl_export void mi_heap_destroy(mi_heap_t* heap); |
196 | mi_decl_export mi_heap_t* mi_heap_set_default(mi_heap_t* heap); |
197 | mi_decl_export mi_heap_t* mi_heap_get_default(void); |
198 | mi_decl_export mi_heap_t* mi_heap_get_backing(void); |
199 | mi_decl_export void mi_heap_collect(mi_heap_t* heap, bool force) mi_attr_noexcept; |
200 | |
201 | mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_heap_malloc(mi_heap_t* heap, size_t size) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size(2); |
202 | mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_heap_zalloc(mi_heap_t* heap, size_t size) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size(2); |
203 | mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_heap_calloc(mi_heap_t* heap, size_t count, size_t size) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size2(2, 3); |
204 | mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_heap_mallocn(mi_heap_t* heap, size_t count, size_t size) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size2(2, 3); |
205 | mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_heap_malloc_small(mi_heap_t* heap, size_t size) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size(2); |
206 | |
207 | mi_decl_nodiscard mi_decl_export void* mi_heap_realloc(mi_heap_t* heap, void* p, size_t newsize) mi_attr_noexcept mi_attr_alloc_size(3); |
208 | mi_decl_nodiscard mi_decl_export void* mi_heap_reallocn(mi_heap_t* heap, void* p, size_t count, size_t size) mi_attr_noexcept mi_attr_alloc_size2(3,4); |
209 | mi_decl_nodiscard mi_decl_export void* mi_heap_reallocf(mi_heap_t* heap, void* p, size_t newsize) mi_attr_noexcept mi_attr_alloc_size(3); |
210 | |
211 | mi_decl_nodiscard mi_decl_export mi_decl_restrict char* mi_heap_strdup(mi_heap_t* heap, const char* s) mi_attr_noexcept mi_attr_malloc; |
212 | mi_decl_nodiscard mi_decl_export mi_decl_restrict char* mi_heap_strndup(mi_heap_t* heap, const char* s, size_t n) mi_attr_noexcept mi_attr_malloc; |
213 | mi_decl_nodiscard mi_decl_export mi_decl_restrict char* mi_heap_realpath(mi_heap_t* heap, const char* fname, char* resolved_name) mi_attr_noexcept mi_attr_malloc; |
214 | |
215 | mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_heap_malloc_aligned(mi_heap_t* heap, size_t size, size_t alignment) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size(2) mi_attr_alloc_align(3); |
216 | mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_heap_malloc_aligned_at(mi_heap_t* heap, size_t size, size_t alignment, size_t offset) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size(2); |
217 | mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_heap_zalloc_aligned(mi_heap_t* heap, size_t size, size_t alignment) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size(2) mi_attr_alloc_align(3); |
218 | mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_heap_zalloc_aligned_at(mi_heap_t* heap, size_t size, size_t alignment, size_t offset) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size(2); |
219 | mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_heap_calloc_aligned(mi_heap_t* heap, size_t count, size_t size, size_t alignment) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size2(2, 3) mi_attr_alloc_align(4); |
220 | mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_heap_calloc_aligned_at(mi_heap_t* heap, size_t count, size_t size, size_t alignment, size_t offset) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size2(2, 3); |
221 | mi_decl_nodiscard mi_decl_export void* mi_heap_realloc_aligned(mi_heap_t* heap, void* p, size_t newsize, size_t alignment) mi_attr_noexcept mi_attr_alloc_size(3) mi_attr_alloc_align(4); |
222 | mi_decl_nodiscard mi_decl_export void* mi_heap_realloc_aligned_at(mi_heap_t* heap, void* p, size_t newsize, size_t alignment, size_t offset) mi_attr_noexcept mi_attr_alloc_size(3); |
223 | |
224 | |
225 | // -------------------------------------------------------------------------------- |
226 | // Zero initialized re-allocation. |
227 | // Only valid on memory that was originally allocated with zero initialization too. |
228 | // e.g. `mi_calloc`, `mi_zalloc`, `mi_zalloc_aligned` etc. |
229 | // see <https://github.com/microsoft/mimalloc/issues/63#issuecomment-508272992> |
230 | // -------------------------------------------------------------------------------- |
231 | |
232 | mi_decl_nodiscard mi_decl_export void* mi_rezalloc(void* p, size_t newsize) mi_attr_noexcept mi_attr_alloc_size(2); |
233 | mi_decl_nodiscard mi_decl_export void* mi_recalloc(void* p, size_t newcount, size_t size) mi_attr_noexcept mi_attr_alloc_size2(2,3); |
234 | |
235 | mi_decl_nodiscard mi_decl_export void* mi_rezalloc_aligned(void* p, size_t newsize, size_t alignment) mi_attr_noexcept mi_attr_alloc_size(2) mi_attr_alloc_align(3); |
236 | mi_decl_nodiscard mi_decl_export void* mi_rezalloc_aligned_at(void* p, size_t newsize, size_t alignment, size_t offset) mi_attr_noexcept mi_attr_alloc_size(2); |
237 | mi_decl_nodiscard mi_decl_export void* mi_recalloc_aligned(void* p, size_t newcount, size_t size, size_t alignment) mi_attr_noexcept mi_attr_alloc_size2(2,3) mi_attr_alloc_align(4); |
238 | mi_decl_nodiscard mi_decl_export void* mi_recalloc_aligned_at(void* p, size_t newcount, size_t size, size_t alignment, size_t offset) mi_attr_noexcept mi_attr_alloc_size2(2,3); |
239 | |
240 | mi_decl_nodiscard mi_decl_export void* mi_heap_rezalloc(mi_heap_t* heap, void* p, size_t newsize) mi_attr_noexcept mi_attr_alloc_size(3); |
241 | mi_decl_nodiscard mi_decl_export void* mi_heap_recalloc(mi_heap_t* heap, void* p, size_t newcount, size_t size) mi_attr_noexcept mi_attr_alloc_size2(3,4); |
242 | |
243 | mi_decl_nodiscard mi_decl_export void* mi_heap_rezalloc_aligned(mi_heap_t* heap, void* p, size_t newsize, size_t alignment) mi_attr_noexcept mi_attr_alloc_size(3) mi_attr_alloc_align(4); |
244 | mi_decl_nodiscard mi_decl_export void* mi_heap_rezalloc_aligned_at(mi_heap_t* heap, void* p, size_t newsize, size_t alignment, size_t offset) mi_attr_noexcept mi_attr_alloc_size(3); |
245 | mi_decl_nodiscard mi_decl_export void* mi_heap_recalloc_aligned(mi_heap_t* heap, void* p, size_t newcount, size_t size, size_t alignment) mi_attr_noexcept mi_attr_alloc_size2(3,4) mi_attr_alloc_align(5); |
246 | mi_decl_nodiscard mi_decl_export void* mi_heap_recalloc_aligned_at(mi_heap_t* heap, void* p, size_t newcount, size_t size, size_t alignment, size_t offset) mi_attr_noexcept mi_attr_alloc_size2(3,4); |
247 | |
248 | |
249 | // ------------------------------------------------------ |
250 | // Analysis |
251 | // ------------------------------------------------------ |
252 | |
253 | mi_decl_export bool mi_heap_contains_block(mi_heap_t* heap, const void* p); |
254 | mi_decl_export bool mi_heap_check_owned(mi_heap_t* heap, const void* p); |
255 | mi_decl_export bool mi_check_owned(const void* p); |
256 | |
257 | // An area of heap space contains blocks of a single size. |
258 | typedef struct mi_heap_area_s { |
259 | void* blocks; // start of the area containing heap blocks |
260 | size_t reserved; // bytes reserved for this area (virtual) |
261 | size_t committed; // current available bytes for this area |
262 | size_t used; // number of allocated blocks |
263 | size_t block_size; // size in bytes of each block |
264 | size_t full_block_size; // size in bytes of a full block including padding and metadata. |
265 | } mi_heap_area_t; |
266 | |
267 | typedef bool (mi_cdecl mi_block_visit_fun)(const mi_heap_t* heap, const mi_heap_area_t* area, void* block, size_t block_size, void* arg); |
268 | |
269 | mi_decl_export bool mi_heap_visit_blocks(const mi_heap_t* heap, bool visit_all_blocks, mi_block_visit_fun* visitor, void* arg); |
270 | |
271 | // Experimental |
272 | mi_decl_nodiscard mi_decl_export bool mi_is_in_heap_region(const void* p) mi_attr_noexcept; |
273 | mi_decl_nodiscard mi_decl_export bool mi_is_redirected(void) mi_attr_noexcept; |
274 | |
275 | mi_decl_export int mi_reserve_huge_os_pages_interleave(size_t pages, size_t numa_nodes, size_t timeout_msecs) mi_attr_noexcept; |
276 | mi_decl_export int mi_reserve_huge_os_pages_at(size_t pages, int numa_node, size_t timeout_msecs) mi_attr_noexcept; |
277 | |
278 | mi_decl_export int mi_reserve_os_memory(size_t size, bool commit, bool allow_large) mi_attr_noexcept; |
279 | mi_decl_export bool mi_manage_os_memory(void* start, size_t size, bool is_committed, bool is_large, bool is_zero, int numa_node) mi_attr_noexcept; |
280 | |
281 | mi_decl_export void mi_debug_show_arenas(void) mi_attr_noexcept; |
282 | |
283 | // Experimental: heaps associated with specific memory arena's |
284 | typedef int mi_arena_id_t; |
285 | mi_decl_export void* mi_arena_area(mi_arena_id_t arena_id, size_t* size); |
286 | mi_decl_export int mi_reserve_huge_os_pages_at_ex(size_t pages, int numa_node, size_t timeout_msecs, bool exclusive, mi_arena_id_t* arena_id) mi_attr_noexcept; |
287 | mi_decl_export int mi_reserve_os_memory_ex(size_t size, bool commit, bool allow_large, bool exclusive, mi_arena_id_t* arena_id) mi_attr_noexcept; |
288 | mi_decl_export bool mi_manage_os_memory_ex(void* start, size_t size, bool is_committed, bool is_large, bool is_zero, int numa_node, bool exclusive, mi_arena_id_t* arena_id) mi_attr_noexcept; |
289 | |
290 | #if MI_MALLOC_VERSION >= 200 |
291 | mi_decl_nodiscard mi_decl_export mi_heap_t* mi_heap_new_in_arena(mi_arena_id_t arena_id); |
292 | #endif |
293 | |
294 | // deprecated |
295 | mi_decl_export int mi_reserve_huge_os_pages(size_t pages, double max_secs, size_t* pages_reserved) mi_attr_noexcept; |
296 | |
297 | |
298 | // ------------------------------------------------------ |
299 | // Convenience |
300 | // ------------------------------------------------------ |
301 | |
302 | #define mi_malloc_tp(tp) ((tp*)mi_malloc(sizeof(tp))) |
303 | #define mi_zalloc_tp(tp) ((tp*)mi_zalloc(sizeof(tp))) |
304 | #define mi_calloc_tp(tp,n) ((tp*)mi_calloc(n,sizeof(tp))) |
305 | #define mi_mallocn_tp(tp,n) ((tp*)mi_mallocn(n,sizeof(tp))) |
306 | #define mi_reallocn_tp(p,tp,n) ((tp*)mi_reallocn(p,n,sizeof(tp))) |
307 | #define mi_recalloc_tp(p,tp,n) ((tp*)mi_recalloc(p,n,sizeof(tp))) |
308 | |
309 | #define mi_heap_malloc_tp(hp,tp) ((tp*)mi_heap_malloc(hp,sizeof(tp))) |
310 | #define mi_heap_zalloc_tp(hp,tp) ((tp*)mi_heap_zalloc(hp,sizeof(tp))) |
311 | #define mi_heap_calloc_tp(hp,tp,n) ((tp*)mi_heap_calloc(hp,n,sizeof(tp))) |
312 | #define mi_heap_mallocn_tp(hp,tp,n) ((tp*)mi_heap_mallocn(hp,n,sizeof(tp))) |
313 | #define mi_heap_reallocn_tp(hp,p,tp,n) ((tp*)mi_heap_reallocn(hp,p,n,sizeof(tp))) |
314 | #define mi_heap_recalloc_tp(hp,p,tp,n) ((tp*)mi_heap_recalloc(hp,p,n,sizeof(tp))) |
315 | |
316 | |
317 | // ------------------------------------------------------ |
318 | // Options |
319 | // ------------------------------------------------------ |
320 | |
321 | typedef enum mi_option_e { |
322 | // stable options |
323 | mi_option_show_errors, |
324 | mi_option_show_stats, |
325 | mi_option_verbose, |
326 | // some of the following options are experimental |
327 | // (deprecated options are kept for binary backward compatibility with v1.x versions) |
328 | mi_option_eager_commit, |
329 | mi_option_deprecated_eager_region_commit, |
330 | mi_option_deprecated_reset_decommits, |
331 | mi_option_large_os_pages, // use large (2MiB) OS pages, implies eager commit |
332 | mi_option_reserve_huge_os_pages, // reserve N huge OS pages (1GiB) at startup |
333 | mi_option_reserve_huge_os_pages_at, // reserve huge OS pages at a specific NUMA node |
334 | mi_option_reserve_os_memory, // reserve specified amount of OS memory at startup |
335 | mi_option_deprecated_segment_cache, |
336 | mi_option_page_reset, |
337 | mi_option_abandoned_page_decommit, |
338 | mi_option_deprecated_segment_reset, |
339 | mi_option_eager_commit_delay, |
340 | mi_option_decommit_delay, |
341 | mi_option_use_numa_nodes, // 0 = use available numa nodes, otherwise use at most N nodes. |
342 | mi_option_limit_os_alloc, // 1 = do not use OS memory for allocation (but only reserved arenas) |
343 | mi_option_os_tag, |
344 | mi_option_max_errors, |
345 | mi_option_max_warnings, |
346 | mi_option_max_segment_reclaim, |
347 | mi_option_allow_decommit, |
348 | mi_option_segment_decommit_delay, |
349 | mi_option_decommit_extend_delay, |
350 | _mi_option_last |
351 | } mi_option_t; |
352 | |
353 | |
354 | mi_decl_nodiscard mi_decl_export bool mi_option_is_enabled(mi_option_t option); |
355 | mi_decl_export void mi_option_enable(mi_option_t option); |
356 | mi_decl_export void mi_option_disable(mi_option_t option); |
357 | mi_decl_export void mi_option_set_enabled(mi_option_t option, bool enable); |
358 | mi_decl_export void mi_option_set_enabled_default(mi_option_t option, bool enable); |
359 | |
360 | mi_decl_nodiscard mi_decl_export long mi_option_get(mi_option_t option); |
361 | mi_decl_nodiscard mi_decl_export long mi_option_get_clamp(mi_option_t option, long min, long max); |
362 | mi_decl_export void mi_option_set(mi_option_t option, long value); |
363 | mi_decl_export void mi_option_set_default(mi_option_t option, long value); |
364 | |
365 | |
366 | // ------------------------------------------------------------------------------------------------------- |
367 | // "mi" prefixed implementations of various posix, Unix, Windows, and C++ allocation functions. |
368 | // (This can be convenient when providing overrides of these functions as done in `mimalloc-override.h`.) |
369 | // note: we use `mi_cfree` as "checked free" and it checks if the pointer is in our heap before free-ing. |
370 | // ------------------------------------------------------------------------------------------------------- |
371 | |
372 | mi_decl_export void mi_cfree(void* p) mi_attr_noexcept; |
373 | mi_decl_export void* mi__expand(void* p, size_t newsize) mi_attr_noexcept; |
374 | mi_decl_nodiscard mi_decl_export size_t mi_malloc_size(const void* p) mi_attr_noexcept; |
375 | mi_decl_nodiscard mi_decl_export size_t mi_malloc_good_size(size_t size) mi_attr_noexcept; |
376 | mi_decl_nodiscard mi_decl_export size_t mi_malloc_usable_size(const void *p) mi_attr_noexcept; |
377 | |
378 | mi_decl_export int mi_posix_memalign(void** p, size_t alignment, size_t size) mi_attr_noexcept; |
379 | mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_memalign(size_t alignment, size_t size) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size(2) mi_attr_alloc_align(1); |
380 | mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_valloc(size_t size) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size(1); |
381 | mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_pvalloc(size_t size) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size(1); |
382 | mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_aligned_alloc(size_t alignment, size_t size) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size(2) mi_attr_alloc_align(1); |
383 | |
384 | mi_decl_nodiscard mi_decl_export void* mi_reallocarray(void* p, size_t count, size_t size) mi_attr_noexcept mi_attr_alloc_size2(2,3); |
385 | mi_decl_nodiscard mi_decl_export int mi_reallocarr(void* p, size_t count, size_t size) mi_attr_noexcept; |
386 | mi_decl_nodiscard mi_decl_export void* mi_aligned_recalloc(void* p, size_t newcount, size_t size, size_t alignment) mi_attr_noexcept; |
387 | mi_decl_nodiscard mi_decl_export void* mi_aligned_offset_recalloc(void* p, size_t newcount, size_t size, size_t alignment, size_t offset) mi_attr_noexcept; |
388 | |
389 | mi_decl_nodiscard mi_decl_export mi_decl_restrict unsigned short* mi_wcsdup(const unsigned short* s) mi_attr_noexcept mi_attr_malloc; |
390 | mi_decl_nodiscard mi_decl_export mi_decl_restrict unsigned char* mi_mbsdup(const unsigned char* s) mi_attr_noexcept mi_attr_malloc; |
391 | mi_decl_export int mi_dupenv_s(char** buf, size_t* size, const char* name) mi_attr_noexcept; |
392 | mi_decl_export int mi_wdupenv_s(unsigned short** buf, size_t* size, const unsigned short* name) mi_attr_noexcept; |
393 | |
394 | mi_decl_export void mi_free_size(void* p, size_t size) mi_attr_noexcept; |
395 | mi_decl_export void mi_free_size_aligned(void* p, size_t size, size_t alignment) mi_attr_noexcept; |
396 | mi_decl_export void mi_free_aligned(void* p, size_t alignment) mi_attr_noexcept; |
397 | |
398 | // The `mi_new` wrappers implement C++ semantics on out-of-memory instead of directly returning `NULL`. |
399 | // (and call `std::get_new_handler` and potentially raise a `std::bad_alloc` exception). |
400 | mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_new(size_t size) mi_attr_malloc mi_attr_alloc_size(1); |
401 | mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_new_aligned(size_t size, size_t alignment) mi_attr_malloc mi_attr_alloc_size(1) mi_attr_alloc_align(2); |
402 | mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_new_nothrow(size_t size) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size(1); |
403 | mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_new_aligned_nothrow(size_t size, size_t alignment) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size(1) mi_attr_alloc_align(2); |
404 | mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_new_n(size_t count, size_t size) mi_attr_malloc mi_attr_alloc_size2(1, 2); |
405 | mi_decl_nodiscard mi_decl_export void* mi_new_realloc(void* p, size_t newsize) mi_attr_alloc_size(2); |
406 | mi_decl_nodiscard mi_decl_export void* mi_new_reallocn(void* p, size_t newcount, size_t size) mi_attr_alloc_size2(2, 3); |
407 | |
408 | #ifdef __cplusplus |
409 | } |
410 | #endif |
411 | |
412 | // --------------------------------------------------------------------------------------------- |
413 | // Implement the C++ std::allocator interface for use in STL containers. |
414 | // (note: see `mimalloc-new-delete.h` for overriding the new/delete operators globally) |
415 | // --------------------------------------------------------------------------------------------- |
416 | #ifdef __cplusplus |
417 | |
418 | #include <cstddef> // std::size_t |
419 | #include <cstdint> // PTRDIFF_MAX |
420 | #if (__cplusplus >= 201103L) || (_MSC_VER > 1900) // C++11 |
421 | #include <type_traits> // std::true_type |
422 | #include <utility> // std::forward |
423 | #endif |
424 | |
425 | template<class T> struct mi_stl_allocator { |
426 | typedef T value_type; |
427 | typedef std::size_t size_type; |
428 | typedef std::ptrdiff_t difference_type; |
429 | typedef value_type& reference; |
430 | typedef value_type const& const_reference; |
431 | typedef value_type* pointer; |
432 | typedef value_type const* const_pointer; |
433 | template <class U> struct rebind { typedef mi_stl_allocator<U> other; }; |
434 | |
435 | mi_stl_allocator() mi_attr_noexcept = default; |
436 | mi_stl_allocator(const mi_stl_allocator&) mi_attr_noexcept = default; |
437 | template<class U> mi_stl_allocator(const mi_stl_allocator<U>&) mi_attr_noexcept { } |
438 | mi_stl_allocator select_on_container_copy_construction() const { return *this; } |
439 | void deallocate(T* p, size_type) { mi_free(p); } |
440 | |
441 | #if (__cplusplus >= 201703L) // C++17 |
442 | mi_decl_nodiscard T* allocate(size_type count) { return static_cast<T*>(mi_new_n(count, sizeof(T))); } |
443 | mi_decl_nodiscard T* allocate(size_type count, const void*) { return allocate(count); } |
444 | #else |
445 | mi_decl_nodiscard pointer allocate(size_type count, const void* = 0) { return static_cast<pointer>(mi_new_n(count, sizeof(value_type))); } |
446 | #endif |
447 | |
448 | #if ((__cplusplus >= 201103L) || (_MSC_VER > 1900)) // C++11 |
449 | using propagate_on_container_copy_assignment = std::true_type; |
450 | using propagate_on_container_move_assignment = std::true_type; |
451 | using propagate_on_container_swap = std::true_type; |
452 | using is_always_equal = std::true_type; |
453 | template <class U, class ...Args> void construct(U* p, Args&& ...args) { ::new(p) U(std::forward<Args>(args)...); } |
454 | template <class U> void destroy(U* p) mi_attr_noexcept { p->~U(); } |
455 | #else |
456 | void construct(pointer p, value_type const& val) { ::new(p) value_type(val); } |
457 | void destroy(pointer p) { p->~value_type(); } |
458 | #endif |
459 | |
460 | size_type max_size() const mi_attr_noexcept { return (PTRDIFF_MAX/sizeof(value_type)); } |
461 | pointer address(reference x) const { return &x; } |
462 | const_pointer address(const_reference x) const { return &x; } |
463 | }; |
464 | |
465 | template<class T1,class T2> bool operator==(const mi_stl_allocator<T1>& , const mi_stl_allocator<T2>& ) mi_attr_noexcept { return true; } |
466 | template<class T1,class T2> bool operator!=(const mi_stl_allocator<T1>& , const mi_stl_allocator<T2>& ) mi_attr_noexcept { return false; } |
467 | #endif // __cplusplus |
468 | |
469 | #endif |
470 | |