microsoft/qdk

Public

mirrored fromhttps://github.com/microsoft/qdkAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
billti/qdk_package

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

source/allocator/mimalloc-sys/mimalloc/include/mimalloc.h

612lines · modecode

1/* ----------------------------------------------------------------------------
2Copyright (c) 2018-2025, Microsoft Research, Daan Leijen
3This is free software; you can redistribute it and/or modify it under the
4terms 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 224 // 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 defined(_HAS_NODISCARD)
32 #define mi_decl_nodiscard _NODISCARD
33#elif (_MSC_VER >= 1700)
34 #define mi_decl_nodiscard _Check_return_
35#else
36 #define mi_decl_nodiscard
37#endif
38
39#if defined(_MSC_VER) || defined(__MINGW32__)
40 #if !defined(MI_SHARED_LIB)
41 #define mi_decl_export
42 #elif defined(MI_SHARED_LIB_EXPORT)
43 #define mi_decl_export __declspec(dllexport)
44 #else
45 #define mi_decl_export __declspec(dllimport)
46 #endif
47 #if defined(__MINGW32__)
48 #define mi_decl_restrict
49 #define mi_attr_malloc __attribute__((malloc))
50 #else
51 #if (_MSC_VER >= 1900) && !defined(__EDG__)
52 #define mi_decl_restrict __declspec(allocator) __declspec(restrict)
53 #else
54 #define mi_decl_restrict __declspec(restrict)
55 #endif
56 #define mi_attr_malloc
57 #endif
58 #define mi_cdecl __cdecl
59 #define mi_attr_alloc_size(s)
60 #define mi_attr_alloc_size2(s1,s2)
61 #define mi_attr_alloc_align(p)
62#elif defined(__GNUC__) // includes clang and icc
63 #if defined(MI_SHARED_LIB) && defined(MI_SHARED_LIB_EXPORT)
64 #define mi_decl_export __attribute__((visibility("default")))
65 #else
66 #define mi_decl_export
67 #endif
68 #define mi_cdecl // leads to warnings... __attribute__((cdecl))
69 #define mi_decl_restrict
70 #define mi_attr_malloc __attribute__((malloc))
71 #if (defined(__clang_major__) && (__clang_major__ < 4)) || (__GNUC__ < 5)
72 #define mi_attr_alloc_size(s)
73 #define mi_attr_alloc_size2(s1,s2)
74 #define mi_attr_alloc_align(p)
75 #elif defined(__INTEL_COMPILER)
76 #define mi_attr_alloc_size(s) __attribute__((alloc_size(s)))
77 #define mi_attr_alloc_size2(s1,s2) __attribute__((alloc_size(s1,s2)))
78 #define mi_attr_alloc_align(p)
79 #else
80 #define mi_attr_alloc_size(s) __attribute__((alloc_size(s)))
81 #define mi_attr_alloc_size2(s1,s2) __attribute__((alloc_size(s1,s2)))
82 #define mi_attr_alloc_align(p) __attribute__((alloc_align(p)))
83 #endif
84#else
85 #define mi_cdecl
86 #define mi_decl_export
87 #define mi_decl_restrict
88 #define mi_attr_malloc
89 #define mi_attr_alloc_size(s)
90 #define mi_attr_alloc_size2(s1,s2)
91 #define mi_attr_alloc_align(p)
92#endif
93
94// ------------------------------------------------------
95// Includes
96// ------------------------------------------------------
97
98#include <stddef.h> // size_t
99#include <stdbool.h> // bool
100#include <stdint.h> // INTPTR_MAX
101
102#ifdef __cplusplus
103extern "C" {
104#endif
105
106// ------------------------------------------------------
107// Standard malloc interface
108// ------------------------------------------------------
109
110mi_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);
111mi_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);
112mi_decl_nodiscard mi_decl_export void* mi_realloc(void* p, size_t newsize) mi_attr_noexcept mi_attr_alloc_size(2);
113mi_decl_export void* mi_expand(void* p, size_t newsize) mi_attr_noexcept mi_attr_alloc_size(2);
114
115mi_decl_export void mi_free(void* p) mi_attr_noexcept;
116mi_decl_nodiscard mi_decl_export mi_decl_restrict char* mi_strdup(const char* s) mi_attr_noexcept mi_attr_malloc;
117mi_decl_nodiscard mi_decl_export mi_decl_restrict char* mi_strndup(const char* s, size_t n) mi_attr_noexcept mi_attr_malloc;
118mi_decl_nodiscard mi_decl_export mi_decl_restrict char* mi_realpath(const char* fname, char* resolved_name) mi_attr_noexcept mi_attr_malloc;
119
120// ------------------------------------------------------
121// Extended functionality
122// ------------------------------------------------------
123#define MI_SMALL_WSIZE_MAX (128)
124#define MI_SMALL_SIZE_MAX (MI_SMALL_WSIZE_MAX*sizeof(void*))
125
126mi_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);
127mi_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);
128mi_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);
129
130mi_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);
131mi_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);
132mi_decl_nodiscard mi_decl_export void* mi_reallocf(void* p, size_t newsize) mi_attr_noexcept mi_attr_alloc_size(2);
133
134mi_decl_nodiscard mi_decl_export size_t mi_usable_size(const void* p) mi_attr_noexcept;
135mi_decl_nodiscard mi_decl_export size_t mi_good_size(size_t size) mi_attr_noexcept;
136
137
138// ------------------------------------------------------
139// Internals
140// ------------------------------------------------------
141
142typedef void (mi_cdecl mi_deferred_free_fun)(bool force, unsigned long long heartbeat, void* arg);
143mi_decl_export void mi_register_deferred_free(mi_deferred_free_fun* deferred_free, void* arg) mi_attr_noexcept;
144
145typedef void (mi_cdecl mi_output_fun)(const char* msg, void* arg);
146mi_decl_export void mi_register_output(mi_output_fun* out, void* arg) mi_attr_noexcept;
147
148typedef void (mi_cdecl mi_error_fun)(int err, void* arg);
149mi_decl_export void mi_register_error(mi_error_fun* fun, void* arg);
150
151mi_decl_export void mi_collect(bool force) mi_attr_noexcept;
152mi_decl_export int mi_version(void) mi_attr_noexcept;
153mi_decl_export void mi_stats_reset(void) mi_attr_noexcept;
154mi_decl_export void mi_stats_merge(void) mi_attr_noexcept;
155mi_decl_export void mi_stats_print(void* out) mi_attr_noexcept; // backward compatibility: `out` is ignored and should be NULL
156mi_decl_export void mi_stats_print_out(mi_output_fun* out, void* arg) mi_attr_noexcept;
157mi_decl_export void mi_thread_stats_print_out(mi_output_fun* out, void* arg) mi_attr_noexcept;
158mi_decl_export void mi_options_print(void) mi_attr_noexcept;
159
160mi_decl_export void mi_process_info(size_t* elapsed_msecs, size_t* user_msecs, size_t* system_msecs,
161 size_t* current_rss, size_t* peak_rss,
162 size_t* current_commit, size_t* peak_commit, size_t* page_faults) mi_attr_noexcept;
163
164
165// Generally do not use the following as these are usually called automatically
166mi_decl_export void mi_process_init(void) mi_attr_noexcept;
167mi_decl_export void mi_cdecl mi_process_done(void) mi_attr_noexcept;
168mi_decl_export void mi_thread_init(void) mi_attr_noexcept;
169mi_decl_export void mi_thread_done(void) mi_attr_noexcept;
170
171
172// -------------------------------------------------------------------------------------
173// Aligned allocation
174// Note that `alignment` always follows `size` for consistency with unaligned
175// allocation, but unfortunately this differs from `posix_memalign` and `aligned_alloc`.
176// -------------------------------------------------------------------------------------
177
178mi_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);
179mi_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);
180mi_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);
181mi_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);
182mi_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);
183mi_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);
184mi_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);
185mi_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);
186
187
188// -------------------------------------------------------------------------------------
189// Heaps: first-class, but can only allocate from the same thread that created it.
190// -------------------------------------------------------------------------------------
191
192struct mi_heap_s;
193typedef struct mi_heap_s mi_heap_t;
194
195mi_decl_nodiscard mi_decl_export mi_heap_t* mi_heap_new(void);
196mi_decl_export void mi_heap_delete(mi_heap_t* heap);
197mi_decl_export void mi_heap_destroy(mi_heap_t* heap);
198mi_decl_export mi_heap_t* mi_heap_set_default(mi_heap_t* heap);
199mi_decl_export mi_heap_t* mi_heap_get_default(void);
200mi_decl_export mi_heap_t* mi_heap_get_backing(void);
201mi_decl_export void mi_heap_collect(mi_heap_t* heap, bool force) mi_attr_noexcept;
202
203mi_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);
204mi_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);
205mi_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);
206mi_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);
207mi_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);
208
209mi_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);
210mi_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);
211mi_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);
212
213mi_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;
214mi_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;
215mi_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;
216
217mi_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);
218mi_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);
219mi_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);
220mi_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);
221mi_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);
222mi_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);
223mi_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);
224mi_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);
225
226
227// --------------------------------------------------------------------------------
228// Zero initialized re-allocation.
229// Only valid on memory that was originally allocated with zero initialization too.
230// e.g. `mi_calloc`, `mi_zalloc`, `mi_zalloc_aligned` etc.
231// see <https://github.com/microsoft/mimalloc/issues/63#issuecomment-508272992>
232// --------------------------------------------------------------------------------
233
234mi_decl_nodiscard mi_decl_export void* mi_rezalloc(void* p, size_t newsize) mi_attr_noexcept mi_attr_alloc_size(2);
235mi_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);
236
237mi_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);
238mi_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);
239mi_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);
240mi_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);
241
242mi_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);
243mi_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);
244
245mi_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);
246mi_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);
247mi_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);
248mi_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);
249
250
251// ------------------------------------------------------
252// Analysis
253// ------------------------------------------------------
254
255mi_decl_export bool mi_heap_contains_block(mi_heap_t* heap, const void* p);
256mi_decl_export bool mi_heap_check_owned(mi_heap_t* heap, const void* p);
257mi_decl_export bool mi_check_owned(const void* p);
258
259// An area of heap space contains blocks of a single size.
260typedef struct mi_heap_area_s {
261 void* blocks; // start of the area containing heap blocks
262 size_t reserved; // bytes reserved for this area (virtual)
263 size_t committed; // current available bytes for this area
264 size_t used; // number of allocated blocks
265 size_t block_size; // size in bytes of each block
266 size_t full_block_size; // size in bytes of a full block including padding and metadata.
267 int heap_tag; // heap tag associated with this area
268} mi_heap_area_t;
269
270typedef 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);
271
272mi_decl_export bool mi_heap_visit_blocks(const mi_heap_t* heap, bool visit_blocks, mi_block_visit_fun* visitor, void* arg);
273
274// Experimental
275mi_decl_nodiscard mi_decl_export bool mi_is_in_heap_region(const void* p) mi_attr_noexcept;
276mi_decl_nodiscard mi_decl_export bool mi_is_redirected(void) mi_attr_noexcept;
277
278mi_decl_export int mi_reserve_huge_os_pages_interleave(size_t pages, size_t numa_nodes, size_t timeout_msecs) mi_attr_noexcept;
279mi_decl_export int mi_reserve_huge_os_pages_at(size_t pages, int numa_node, size_t timeout_msecs) mi_attr_noexcept;
280
281mi_decl_export int mi_reserve_os_memory(size_t size, bool commit, bool allow_large) mi_attr_noexcept;
282mi_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;
283
284mi_decl_export void mi_debug_show_arenas(void) mi_attr_noexcept;
285mi_decl_export void mi_arenas_print(void) mi_attr_noexcept;
286
287// Experimental: heaps associated with specific memory arena's
288typedef int mi_arena_id_t;
289mi_decl_export void* mi_arena_area(mi_arena_id_t arena_id, size_t* size);
290mi_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;
291mi_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;
292mi_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;
293
294#if MI_MALLOC_VERSION >= 182
295// Create a heap that only allocates in the specified arena
296mi_decl_nodiscard mi_decl_export mi_heap_t* mi_heap_new_in_arena(mi_arena_id_t arena_id);
297#endif
298
299
300// Experimental: allow sub-processes whose memory areas stay separated (and no reclamation between them)
301// Used for example for separate interpreters in one process.
302typedef void* mi_subproc_id_t;
303mi_decl_export mi_subproc_id_t mi_subproc_main(void);
304mi_decl_export mi_subproc_id_t mi_subproc_new(void);
305mi_decl_export void mi_subproc_delete(mi_subproc_id_t subproc);
306mi_decl_export void mi_subproc_add_current_thread(mi_subproc_id_t subproc); // this should be called right after a thread is created (and no allocation has taken place yet)
307
308// Experimental: visit abandoned heap areas (that are not owned by a specific heap)
309mi_decl_export bool mi_abandoned_visit_blocks(mi_subproc_id_t subproc_id, int heap_tag, bool visit_blocks, mi_block_visit_fun* visitor, void* arg);
310
311// Experimental: objects followed by a guard page.
312// A sample rate of 0 disables guarded objects, while 1 uses a guard page for every object.
313// A seed of 0 uses a random start point. Only objects within the size bound are eligable for guard pages.
314mi_decl_export void mi_heap_guarded_set_sample_rate(mi_heap_t* heap, size_t sample_rate, size_t seed);
315mi_decl_export void mi_heap_guarded_set_size_bound(mi_heap_t* heap, size_t min, size_t max);
316
317// Experimental: communicate that the thread is part of a threadpool
318mi_decl_export void mi_thread_set_in_threadpool(void) mi_attr_noexcept;
319
320// Experimental: create a new heap with a specified heap tag. Set `allow_destroy` to false to allow the thread
321// to reclaim abandoned memory (with a compatible heap_tag and arena_id) but in that case `mi_heap_destroy` will
322// fall back to `mi_heap_delete`.
323mi_decl_nodiscard mi_decl_export mi_heap_t* mi_heap_new_ex(int heap_tag, bool allow_destroy, mi_arena_id_t arena_id);
324
325// deprecated
326mi_decl_export int mi_reserve_huge_os_pages(size_t pages, double max_secs, size_t* pages_reserved) mi_attr_noexcept;
327mi_decl_export void mi_collect_reduce(size_t target_thread_owned) mi_attr_noexcept;
328
329
330
331// ------------------------------------------------------
332// Convenience
333// ------------------------------------------------------
334
335#define mi_malloc_tp(tp) ((tp*)mi_malloc(sizeof(tp)))
336#define mi_zalloc_tp(tp) ((tp*)mi_zalloc(sizeof(tp)))
337#define mi_calloc_tp(tp,n) ((tp*)mi_calloc(n,sizeof(tp)))
338#define mi_mallocn_tp(tp,n) ((tp*)mi_mallocn(n,sizeof(tp)))
339#define mi_reallocn_tp(p,tp,n) ((tp*)mi_reallocn(p,n,sizeof(tp)))
340#define mi_recalloc_tp(p,tp,n) ((tp*)mi_recalloc(p,n,sizeof(tp)))
341
342#define mi_heap_malloc_tp(hp,tp) ((tp*)mi_heap_malloc(hp,sizeof(tp)))
343#define mi_heap_zalloc_tp(hp,tp) ((tp*)mi_heap_zalloc(hp,sizeof(tp)))
344#define mi_heap_calloc_tp(hp,tp,n) ((tp*)mi_heap_calloc(hp,n,sizeof(tp)))
345#define mi_heap_mallocn_tp(hp,tp,n) ((tp*)mi_heap_mallocn(hp,n,sizeof(tp)))
346#define mi_heap_reallocn_tp(hp,p,tp,n) ((tp*)mi_heap_reallocn(hp,p,n,sizeof(tp)))
347#define mi_heap_recalloc_tp(hp,p,tp,n) ((tp*)mi_heap_recalloc(hp,p,n,sizeof(tp)))
348
349
350// ------------------------------------------------------
351// Options
352// ------------------------------------------------------
353
354typedef enum mi_option_e {
355 // stable options
356 mi_option_show_errors, // print error messages
357 mi_option_show_stats, // print statistics on termination
358 mi_option_verbose, // print verbose messages
359 // advanced options
360 mi_option_eager_commit, // eager commit segments? (after `eager_commit_delay` segments) (=1)
361 mi_option_arena_eager_commit, // eager commit arenas? Use 2 to enable just on overcommit systems (=2)
362 mi_option_purge_decommits, // should a memory purge decommit? (=1). Set to 0 to use memory reset on a purge (instead of decommit)
363 mi_option_allow_large_os_pages, // allow large (2 or 4 MiB) OS pages, implies eager commit. If false, also disables THP for the process.
364 mi_option_reserve_huge_os_pages, // reserve N huge OS pages (1GiB pages) at startup
365 mi_option_reserve_huge_os_pages_at, // reserve huge OS pages at a specific NUMA node
366 mi_option_reserve_os_memory, // reserve specified amount of OS memory in an arena at startup (internally, this value is in KiB; use `mi_option_get_size`)
367 mi_option_deprecated_segment_cache,
368 mi_option_deprecated_page_reset,
369 mi_option_abandoned_page_purge, // immediately purge delayed purges on thread termination
370 mi_option_deprecated_segment_reset,
371 mi_option_eager_commit_delay, // the first N segments per thread are not eagerly committed (but per page in the segment on demand)
372 mi_option_purge_delay, // memory purging is delayed by N milli seconds; use 0 for immediate purging or -1 for no purging at all. (=10)
373 mi_option_use_numa_nodes, // 0 = use all available numa nodes, otherwise use at most N nodes.
374 mi_option_disallow_os_alloc, // 1 = do not use OS memory for allocation (but only programmatically reserved arenas)
375 mi_option_os_tag, // tag used for OS logging (macOS only for now) (=100)
376 mi_option_max_errors, // issue at most N error messages
377 mi_option_max_warnings, // issue at most N warning messages
378 mi_option_max_segment_reclaim, // max. percentage of the abandoned segments can be reclaimed per try (=10%)
379 mi_option_destroy_on_exit, // if set, release all memory on exit; sometimes used for dynamic unloading but can be unsafe
380 mi_option_arena_reserve, // initial memory size for arena reservation (= 1 GiB on 64-bit) (internally, this value is in KiB; use `mi_option_get_size`)
381 mi_option_arena_purge_mult, // multiplier for `purge_delay` for the purging delay for arenas (=10)
382 mi_option_purge_extend_delay,
383 mi_option_abandoned_reclaim_on_free, // allow to reclaim an abandoned segment on a free (=1)
384 mi_option_disallow_arena_alloc, // 1 = do not use arena's for allocation (except if using specific arena id's)
385 mi_option_retry_on_oom, // retry on out-of-memory for N milli seconds (=400), set to 0 to disable retries. (only on windows)
386 mi_option_visit_abandoned, // allow visiting heap blocks from abandoned threads (=0)
387 mi_option_guarded_min, // only used when building with MI_GUARDED: minimal rounded object size for guarded objects (=0)
388 mi_option_guarded_max, // only used when building with MI_GUARDED: maximal rounded object size for guarded objects (=0)
389 mi_option_guarded_precise, // disregard minimal alignment requirement to always place guarded blocks exactly in front of a guard page (=0)
390 mi_option_guarded_sample_rate, // 1 out of N allocations in the min/max range will be guarded (=1000)
391 mi_option_guarded_sample_seed, // can be set to allow for a (more) deterministic re-execution when a guard page is triggered (=0)
392 mi_option_target_segments_per_thread, // experimental (=0)
393 mi_option_generic_collect, // collect heaps every N (=10000) generic allocation calls
394 _mi_option_last,
395 // legacy option names
396 mi_option_large_os_pages = mi_option_allow_large_os_pages,
397 mi_option_eager_region_commit = mi_option_arena_eager_commit,
398 mi_option_reset_decommits = mi_option_purge_decommits,
399 mi_option_reset_delay = mi_option_purge_delay,
400 mi_option_abandoned_page_reset = mi_option_abandoned_page_purge,
401 mi_option_limit_os_alloc = mi_option_disallow_os_alloc
402} mi_option_t;
403
404
405mi_decl_nodiscard mi_decl_export bool mi_option_is_enabled(mi_option_t option);
406mi_decl_export void mi_option_enable(mi_option_t option);
407mi_decl_export void mi_option_disable(mi_option_t option);
408mi_decl_export void mi_option_set_enabled(mi_option_t option, bool enable);
409mi_decl_export void mi_option_set_enabled_default(mi_option_t option, bool enable);
410
411mi_decl_nodiscard mi_decl_export long mi_option_get(mi_option_t option);
412mi_decl_nodiscard mi_decl_export long mi_option_get_clamp(mi_option_t option, long min, long max);
413mi_decl_nodiscard mi_decl_export size_t mi_option_get_size(mi_option_t option);
414mi_decl_export void mi_option_set(mi_option_t option, long value);
415mi_decl_export void mi_option_set_default(mi_option_t option, long value);
416
417
418// -------------------------------------------------------------------------------------------------------
419// "mi" prefixed implementations of various posix, Unix, Windows, and C++ allocation functions.
420// (This can be convenient when providing overrides of these functions as done in `mimalloc-override.h`.)
421// note: we use `mi_cfree` as "checked free" and it checks if the pointer is in our heap before free-ing.
422// -------------------------------------------------------------------------------------------------------
423
424mi_decl_export void mi_cfree(void* p) mi_attr_noexcept;
425mi_decl_export void* mi__expand(void* p, size_t newsize) mi_attr_noexcept;
426mi_decl_nodiscard mi_decl_export size_t mi_malloc_size(const void* p) mi_attr_noexcept;
427mi_decl_nodiscard mi_decl_export size_t mi_malloc_good_size(size_t size) mi_attr_noexcept;
428mi_decl_nodiscard mi_decl_export size_t mi_malloc_usable_size(const void *p) mi_attr_noexcept;
429
430mi_decl_export int mi_posix_memalign(void** p, size_t alignment, size_t size) mi_attr_noexcept;
431mi_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);
432mi_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);
433mi_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);
434mi_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);
435
436mi_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);
437mi_decl_nodiscard mi_decl_export int mi_reallocarr(void* p, size_t count, size_t size) mi_attr_noexcept;
438mi_decl_nodiscard mi_decl_export void* mi_aligned_recalloc(void* p, size_t newcount, size_t size, size_t alignment) mi_attr_noexcept;
439mi_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;
440
441mi_decl_nodiscard mi_decl_export mi_decl_restrict unsigned short* mi_wcsdup(const unsigned short* s) mi_attr_noexcept mi_attr_malloc;
442mi_decl_nodiscard mi_decl_export mi_decl_restrict unsigned char* mi_mbsdup(const unsigned char* s) mi_attr_noexcept mi_attr_malloc;
443mi_decl_export int mi_dupenv_s(char** buf, size_t* size, const char* name) mi_attr_noexcept;
444mi_decl_export int mi_wdupenv_s(unsigned short** buf, size_t* size, const unsigned short* name) mi_attr_noexcept;
445
446mi_decl_export void mi_free_size(void* p, size_t size) mi_attr_noexcept;
447mi_decl_export void mi_free_size_aligned(void* p, size_t size, size_t alignment) mi_attr_noexcept;
448mi_decl_export void mi_free_aligned(void* p, size_t alignment) mi_attr_noexcept;
449
450// The `mi_new` wrappers implement C++ semantics on out-of-memory instead of directly returning `NULL`.
451// (and call `std::get_new_handler` and potentially raise a `std::bad_alloc` exception).
452mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_new(size_t size) mi_attr_malloc mi_attr_alloc_size(1);
453mi_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);
454mi_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);
455mi_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);
456mi_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);
457mi_decl_nodiscard mi_decl_export void* mi_new_realloc(void* p, size_t newsize) mi_attr_alloc_size(2);
458mi_decl_nodiscard mi_decl_export void* mi_new_reallocn(void* p, size_t newcount, size_t size) mi_attr_alloc_size2(2, 3);
459
460mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_heap_alloc_new(mi_heap_t* heap, size_t size) mi_attr_malloc mi_attr_alloc_size(2);
461mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_heap_alloc_new_n(mi_heap_t* heap, size_t count, size_t size) mi_attr_malloc mi_attr_alloc_size2(2, 3);
462
463#ifdef __cplusplus
464}
465#endif
466
467// ---------------------------------------------------------------------------------------------
468// Implement the C++ std::allocator interface for use in STL containers.
469// (note: see `mimalloc-new-delete.h` for overriding the new/delete operators globally)
470// ---------------------------------------------------------------------------------------------
471#ifdef __cplusplus
472
473#include <cstddef> // std::size_t
474#include <cstdint> // PTRDIFF_MAX
475#if (__cplusplus >= 201103L) || (_MSC_VER > 1900) // C++11
476#include <type_traits> // std::true_type
477#include <utility> // std::forward
478#endif
479
480template<class T> struct _mi_stl_allocator_common {
481 typedef T value_type;
482 typedef std::size_t size_type;
483 typedef std::ptrdiff_t difference_type;
484 typedef value_type& reference;
485 typedef value_type const& const_reference;
486 typedef value_type* pointer;
487 typedef value_type const* const_pointer;
488
489 #if ((__cplusplus >= 201103L) || (_MSC_VER > 1900)) // C++11
490 using propagate_on_container_copy_assignment = std::true_type;
491 using propagate_on_container_move_assignment = std::true_type;
492 using propagate_on_container_swap = std::true_type;
493 template <class U, class ...Args> void construct(U* p, Args&& ...args) { ::new(p) U(std::forward<Args>(args)...); }
494 template <class U> void destroy(U* p) mi_attr_noexcept { p->~U(); }
495 #else
496 void construct(pointer p, value_type const& val) { ::new(p) value_type(val); }
497 void destroy(pointer p) { p->~value_type(); }
498 #endif
499
500 size_type max_size() const mi_attr_noexcept { return (PTRDIFF_MAX/sizeof(value_type)); }
501 pointer address(reference x) const { return &x; }
502 const_pointer address(const_reference x) const { return &x; }
503};
504
505template<class T> struct mi_stl_allocator : public _mi_stl_allocator_common<T> {
506 using typename _mi_stl_allocator_common<T>::size_type;
507 using typename _mi_stl_allocator_common<T>::value_type;
508 using typename _mi_stl_allocator_common<T>::pointer;
509 template <class U> struct rebind { typedef mi_stl_allocator<U> other; };
510
511 mi_stl_allocator() mi_attr_noexcept = default;
512 mi_stl_allocator(const mi_stl_allocator&) mi_attr_noexcept = default;
513 template<class U> mi_stl_allocator(const mi_stl_allocator<U>&) mi_attr_noexcept { }
514 mi_stl_allocator select_on_container_copy_construction() const { return *this; }
515 void deallocate(T* p, size_type) { mi_free(p); }
516
517 #if (__cplusplus >= 201703L) // C++17
518 mi_decl_nodiscard T* allocate(size_type count) { return static_cast<T*>(mi_new_n(count, sizeof(T))); }
519 mi_decl_nodiscard T* allocate(size_type count, const void*) { return allocate(count); }
520 #else
521 mi_decl_nodiscard pointer allocate(size_type count, const void* = 0) { return static_cast<pointer>(mi_new_n(count, sizeof(value_type))); }
522 #endif
523
524 #if ((__cplusplus >= 201103L) || (_MSC_VER > 1900)) // C++11
525 using is_always_equal = std::true_type;
526 #endif
527};
528
529template<class T1,class T2> bool operator==(const mi_stl_allocator<T1>& , const mi_stl_allocator<T2>& ) mi_attr_noexcept { return true; }
530template<class T1,class T2> bool operator!=(const mi_stl_allocator<T1>& , const mi_stl_allocator<T2>& ) mi_attr_noexcept { return false; }
531
532
533#if (__cplusplus >= 201103L) || (_MSC_VER >= 1900) // C++11
534#define MI_HAS_HEAP_STL_ALLOCATOR 1
535
536#include <memory> // std::shared_ptr
537
538// Common base class for STL allocators in a specific heap
539template<class T, bool _mi_destroy> struct _mi_heap_stl_allocator_common : public _mi_stl_allocator_common<T> {
540 using typename _mi_stl_allocator_common<T>::size_type;
541 using typename _mi_stl_allocator_common<T>::value_type;
542 using typename _mi_stl_allocator_common<T>::pointer;
543
544 _mi_heap_stl_allocator_common(mi_heap_t* hp) : heap(hp, [](mi_heap_t*) {}) {} /* will not delete nor destroy the passed in heap */
545
546 #if (__cplusplus >= 201703L) // C++17
547 mi_decl_nodiscard T* allocate(size_type count) { return static_cast<T*>(mi_heap_alloc_new_n(this->heap.get(), count, sizeof(T))); }
548 mi_decl_nodiscard T* allocate(size_type count, const void*) { return allocate(count); }
549 #else
550 mi_decl_nodiscard pointer allocate(size_type count, const void* = 0) { return static_cast<pointer>(mi_heap_alloc_new_n(this->heap.get(), count, sizeof(value_type))); }
551 #endif
552
553 #if ((__cplusplus >= 201103L) || (_MSC_VER > 1900)) // C++11
554 using is_always_equal = std::false_type;
555 #endif
556
557 void collect(bool force) { mi_heap_collect(this->heap.get(), force); }
558 template<class U> bool is_equal(const _mi_heap_stl_allocator_common<U, _mi_destroy>& x) const { return (this->heap == x.heap); }
559
560protected:
561 std::shared_ptr<mi_heap_t> heap;
562 template<class U, bool D> friend struct _mi_heap_stl_allocator_common;
563
564 _mi_heap_stl_allocator_common() {
565 mi_heap_t* hp = mi_heap_new();
566 this->heap.reset(hp, (_mi_destroy ? &heap_destroy : &heap_delete)); /* calls heap_delete/destroy when the refcount drops to zero */
567 }
568 _mi_heap_stl_allocator_common(const _mi_heap_stl_allocator_common& x) mi_attr_noexcept : heap(x.heap) { }
569 template<class U> _mi_heap_stl_allocator_common(const _mi_heap_stl_allocator_common<U, _mi_destroy>& x) mi_attr_noexcept : heap(x.heap) { }
570
571private:
572 static void heap_delete(mi_heap_t* hp) { if (hp != NULL) { mi_heap_delete(hp); } }
573 static void heap_destroy(mi_heap_t* hp) { if (hp != NULL) { mi_heap_destroy(hp); } }
574};
575
576// STL allocator allocation in a specific heap
577template<class T> struct mi_heap_stl_allocator : public _mi_heap_stl_allocator_common<T, false> {
578 using typename _mi_heap_stl_allocator_common<T, false>::size_type;
579 mi_heap_stl_allocator() : _mi_heap_stl_allocator_common<T, false>() { } // creates fresh heap that is deleted when the destructor is called
580 mi_heap_stl_allocator(mi_heap_t* hp) : _mi_heap_stl_allocator_common<T, false>(hp) { } // no delete nor destroy on the passed in heap
581 template<class U> mi_heap_stl_allocator(const mi_heap_stl_allocator<U>& x) mi_attr_noexcept : _mi_heap_stl_allocator_common<T, false>(x) { }
582
583 mi_heap_stl_allocator select_on_container_copy_construction() const { return *this; }
584 void deallocate(T* p, size_type) { mi_free(p); }
585 template<class U> struct rebind { typedef mi_heap_stl_allocator<U> other; };
586};
587
588template<class T1, class T2> bool operator==(const mi_heap_stl_allocator<T1>& x, const mi_heap_stl_allocator<T2>& y) mi_attr_noexcept { return (x.is_equal(y)); }
589template<class T1, class T2> bool operator!=(const mi_heap_stl_allocator<T1>& x, const mi_heap_stl_allocator<T2>& y) mi_attr_noexcept { return (!x.is_equal(y)); }
590
591
592// STL allocator allocation in a specific heap, where `free` does nothing and
593// the heap is destroyed in one go on destruction -- use with care!
594template<class T> struct mi_heap_destroy_stl_allocator : public _mi_heap_stl_allocator_common<T, true> {
595 using typename _mi_heap_stl_allocator_common<T, true>::size_type;
596 mi_heap_destroy_stl_allocator() : _mi_heap_stl_allocator_common<T, true>() { } // creates fresh heap that is destroyed when the destructor is called
597 mi_heap_destroy_stl_allocator(mi_heap_t* hp) : _mi_heap_stl_allocator_common<T, true>(hp) { } // no delete nor destroy on the passed in heap
598 template<class U> mi_heap_destroy_stl_allocator(const mi_heap_destroy_stl_allocator<U>& x) mi_attr_noexcept : _mi_heap_stl_allocator_common<T, true>(x) { }
599
600 mi_heap_destroy_stl_allocator select_on_container_copy_construction() const { return *this; }
601 void deallocate(T*, size_type) { /* do nothing as we destroy the heap on destruct. */ }
602 template<class U> struct rebind { typedef mi_heap_destroy_stl_allocator<U> other; };
603};
604
605template<class T1, class T2> bool operator==(const mi_heap_destroy_stl_allocator<T1>& x, const mi_heap_destroy_stl_allocator<T2>& y) mi_attr_noexcept { return (x.is_equal(y)); }
606template<class T1, class T2> bool operator!=(const mi_heap_destroy_stl_allocator<T1>& x, const mi_heap_destroy_stl_allocator<T2>& y) mi_attr_noexcept { return (!x.is_equal(y)); }
607
608#endif // C++11
609
610#endif // __cplusplus
611
612#endif
613