mirror of
https://github.com/microsoft/mimalloc.git
synced 2025-05-08 00:09:31 +03:00
merge from dev, upstream of python/cpython#113263
This commit is contained in:
commit
b822a44cfe
4 changed files with 50 additions and 30 deletions
|
@ -88,6 +88,7 @@ mi_threadid_t _mi_thread_id(void) mi_attr_noexcept;
|
||||||
mi_heap_t* _mi_heap_main_get(void); // statically allocated main backing heap
|
mi_heap_t* _mi_heap_main_get(void); // statically allocated main backing heap
|
||||||
void _mi_thread_done(mi_heap_t* heap);
|
void _mi_thread_done(mi_heap_t* heap);
|
||||||
void _mi_thread_data_collect(void);
|
void _mi_thread_data_collect(void);
|
||||||
|
void _mi_tld_init(mi_tld_t* tld, mi_heap_t* bheap);
|
||||||
|
|
||||||
// os.c
|
// os.c
|
||||||
void _mi_os_init(void); // called from process init
|
void _mi_os_init(void); // called from process init
|
||||||
|
@ -186,6 +187,7 @@ size_t _mi_bin_size(uint8_t bin); // for stats
|
||||||
uint8_t _mi_bin(size_t size); // for stats
|
uint8_t _mi_bin(size_t size); // for stats
|
||||||
|
|
||||||
// "heap.c"
|
// "heap.c"
|
||||||
|
void _mi_heap_init(mi_heap_t* heap, mi_tld_t* tld, mi_arena_id_t arena_id);
|
||||||
void _mi_heap_destroy_pages(mi_heap_t* heap);
|
void _mi_heap_destroy_pages(mi_heap_t* heap);
|
||||||
void _mi_heap_collect_abandon(mi_heap_t* heap);
|
void _mi_heap_collect_abandon(mi_heap_t* heap);
|
||||||
void _mi_heap_set_default_direct(mi_heap_t* heap);
|
void _mi_heap_set_default_direct(mi_heap_t* heap);
|
||||||
|
|
|
@ -222,7 +222,13 @@ extern bool _mi_process_is_initialized; // has mi_process_init been
|
||||||
static inline mi_threadid_t _mi_prim_thread_id(void) mi_attr_noexcept;
|
static inline mi_threadid_t _mi_prim_thread_id(void) mi_attr_noexcept;
|
||||||
|
|
||||||
// Get a unique id for the current thread.
|
// Get a unique id for the current thread.
|
||||||
#if defined(_WIN32)
|
#if defined(MI_PRIM_THREAD_ID)
|
||||||
|
|
||||||
|
static inline mi_threadid_t _mi_prim_thread_id(void) mi_attr_noexcept {
|
||||||
|
return MI_PRIM_THREAD_ID(); // used for example by CPython for a free threaded build (see python/cpython#115488)
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif defined(_WIN32)
|
||||||
|
|
||||||
#ifndef WIN32_LEAN_AND_MEAN
|
#ifndef WIN32_LEAN_AND_MEAN
|
||||||
#define WIN32_LEAN_AND_MEAN
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
|
35
src/heap.c
35
src/heap.c
|
@ -128,6 +128,9 @@ static void mi_heap_collect_ex(mi_heap_t* heap, mi_collect_t collect)
|
||||||
const bool force = (collect >= MI_FORCE);
|
const bool force = (collect >= MI_FORCE);
|
||||||
_mi_deferred_free(heap, force);
|
_mi_deferred_free(heap, force);
|
||||||
|
|
||||||
|
// python/cpython#112532: we may be called from a thread that is not the owner of the heap
|
||||||
|
const bool is_main_thread = (_mi_is_main_thread() && heap->thread_id == _mi_thread_id());
|
||||||
|
|
||||||
// note: never reclaim on collect but leave it to threads that need storage to reclaim
|
// note: never reclaim on collect but leave it to threads that need storage to reclaim
|
||||||
const bool force_main =
|
const bool force_main =
|
||||||
#ifdef NDEBUG
|
#ifdef NDEBUG
|
||||||
|
@ -135,7 +138,7 @@ static void mi_heap_collect_ex(mi_heap_t* heap, mi_collect_t collect)
|
||||||
#else
|
#else
|
||||||
collect >= MI_FORCE
|
collect >= MI_FORCE
|
||||||
#endif
|
#endif
|
||||||
&& _mi_is_main_thread() && mi_heap_is_backing(heap) && !heap->no_reclaim;
|
&& is_main_thread && mi_heap_is_backing(heap) && !heap->no_reclaim;
|
||||||
|
|
||||||
if (force_main) {
|
if (force_main) {
|
||||||
// the main thread is abandoned (end-of-program), try to reclaim all abandoned segments.
|
// the main thread is abandoned (end-of-program), try to reclaim all abandoned segments.
|
||||||
|
@ -164,7 +167,7 @@ static void mi_heap_collect_ex(mi_heap_t* heap, mi_collect_t collect)
|
||||||
_mi_abandoned_collect(heap, collect == MI_FORCE /* force? */, &heap->tld->segments);
|
_mi_abandoned_collect(heap, collect == MI_FORCE /* force? */, &heap->tld->segments);
|
||||||
|
|
||||||
// if forced, collect thread data cache on program-exit (or shared library unload)
|
// if forced, collect thread data cache on program-exit (or shared library unload)
|
||||||
if (force && _mi_is_main_thread() && mi_heap_is_backing(heap)) {
|
if (force && is_main_thread && mi_heap_is_backing(heap)) {
|
||||||
_mi_thread_data_collect(); // collect thread data cache
|
_mi_thread_data_collect(); // collect thread data cache
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -208,19 +211,29 @@ mi_heap_t* mi_heap_get_backing(void) {
|
||||||
return bheap;
|
return bheap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _mi_heap_init(mi_heap_t* heap, mi_tld_t* tld, mi_arena_id_t arena_id) {
|
||||||
|
_mi_memcpy_aligned(heap, &_mi_heap_empty, sizeof(mi_heap_t));
|
||||||
|
heap->tld = tld;
|
||||||
|
heap->thread_id = _mi_thread_id();
|
||||||
|
heap->arena_id = arena_id;
|
||||||
|
if (heap == tld->heap_backing) {
|
||||||
|
_mi_random_init(&heap->random);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
_mi_random_split(&tld->heap_backing->random, &heap->random);
|
||||||
|
}
|
||||||
|
heap->cookie = _mi_heap_random_next(heap) | 1;
|
||||||
|
heap->keys[0] = _mi_heap_random_next(heap);
|
||||||
|
heap->keys[1] = _mi_heap_random_next(heap);
|
||||||
|
}
|
||||||
|
|
||||||
mi_decl_nodiscard mi_heap_t* mi_heap_new_in_arena(mi_arena_id_t arena_id) {
|
mi_decl_nodiscard mi_heap_t* mi_heap_new_in_arena(mi_arena_id_t arena_id) {
|
||||||
mi_heap_t* bheap = mi_heap_get_backing();
|
mi_heap_t* bheap = mi_heap_get_backing();
|
||||||
mi_heap_t* heap = mi_heap_malloc_tp(bheap, mi_heap_t); // todo: OS allocate in secure mode?
|
mi_heap_t* heap = mi_heap_malloc_tp(bheap, mi_heap_t); // todo: OS allocate in secure mode?
|
||||||
if (heap == NULL) return NULL;
|
if (heap == NULL) return NULL;
|
||||||
_mi_memcpy_aligned(heap, &_mi_heap_empty, sizeof(mi_heap_t));
|
_mi_heap_init(heap, bheap->tld, arena_id);
|
||||||
heap->tld = bheap->tld;
|
// don't reclaim abandoned pages or otherwise destroy is unsafe
|
||||||
heap->thread_id = _mi_thread_id();
|
heap->no_reclaim = true;
|
||||||
heap->arena_id = arena_id;
|
|
||||||
_mi_random_split(&bheap->random, &heap->random);
|
|
||||||
heap->cookie = _mi_heap_random_next(heap) | 1;
|
|
||||||
heap->keys[0] = _mi_heap_random_next(heap);
|
|
||||||
heap->keys[1] = _mi_heap_random_next(heap);
|
|
||||||
heap->no_reclaim = true; // don't reclaim abandoned pages or otherwise destroy is unsafe
|
|
||||||
// push on the thread local heaps list
|
// push on the thread local heaps list
|
||||||
heap->next = heap->tld->heaps;
|
heap->next = heap->tld->heaps;
|
||||||
heap->tld->heaps = heap;
|
heap->tld->heaps = heap;
|
||||||
|
|
35
src/init.c
35
src/init.c
|
@ -286,7 +286,7 @@ void _mi_thread_data_collect(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize the thread local default heap, called from `mi_thread_init`
|
// Initialize the thread local default heap, called from `mi_thread_init`
|
||||||
static bool _mi_heap_init(void) {
|
static bool _mi_thread_heap_init(void) {
|
||||||
if (mi_heap_is_initialized(mi_prim_get_default_heap())) return true;
|
if (mi_heap_is_initialized(mi_prim_get_default_heap())) return true;
|
||||||
if (_mi_is_main_thread()) {
|
if (_mi_is_main_thread()) {
|
||||||
// mi_assert_internal(_mi_heap_main.thread_id != 0); // can happen on freeBSD where alloc is called before any initialization
|
// mi_assert_internal(_mi_heap_main.thread_id != 0); // can happen on freeBSD where alloc is called before any initialization
|
||||||
|
@ -302,26 +302,25 @@ static bool _mi_heap_init(void) {
|
||||||
|
|
||||||
mi_tld_t* tld = &td->tld;
|
mi_tld_t* tld = &td->tld;
|
||||||
mi_heap_t* heap = &td->heap;
|
mi_heap_t* heap = &td->heap;
|
||||||
_mi_memcpy_aligned(tld, &tld_empty, sizeof(*tld));
|
_mi_tld_init(tld, heap); // must be before `_mi_heap_init`
|
||||||
_mi_memcpy_aligned(heap, &_mi_heap_empty, sizeof(*heap));
|
_mi_heap_init(heap, tld, _mi_arena_id_none());
|
||||||
heap->thread_id = _mi_thread_id();
|
_mi_heap_set_default_direct(heap);
|
||||||
_mi_random_init(&heap->random);
|
|
||||||
heap->cookie = _mi_heap_random_next(heap) | 1;
|
|
||||||
heap->keys[0] = _mi_heap_random_next(heap);
|
|
||||||
heap->keys[1] = _mi_heap_random_next(heap);
|
|
||||||
heap->tld = tld;
|
|
||||||
tld->heap_backing = heap;
|
|
||||||
tld->heaps = heap;
|
|
||||||
tld->segments.stats = &tld->stats;
|
|
||||||
tld->segments.os = &tld->os;
|
|
||||||
tld->os.stats = &tld->stats;
|
|
||||||
_mi_heap_set_default_direct(heap);
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// initialize thread local data
|
||||||
|
void _mi_tld_init(mi_tld_t* tld, mi_heap_t* bheap) {
|
||||||
|
_mi_memcpy_aligned(tld, &tld_empty, sizeof(mi_tld_t));
|
||||||
|
tld->heap_backing = bheap;
|
||||||
|
tld->heaps = bheap;
|
||||||
|
tld->segments.stats = &tld->stats;
|
||||||
|
tld->segments.os = &tld->os;
|
||||||
|
tld->os.stats = &tld->stats;
|
||||||
|
}
|
||||||
|
|
||||||
// Free the thread local default heap (called from `mi_thread_done`)
|
// Free the thread local default heap (called from `mi_thread_done`)
|
||||||
static bool _mi_heap_done(mi_heap_t* heap) {
|
static bool _mi_thread_heap_done(mi_heap_t* heap) {
|
||||||
if (!mi_heap_is_initialized(heap)) return true;
|
if (!mi_heap_is_initialized(heap)) return true;
|
||||||
|
|
||||||
// reset default heap
|
// reset default heap
|
||||||
|
@ -418,7 +417,7 @@ void mi_thread_init(void) mi_attr_noexcept
|
||||||
// initialize the thread local default heap
|
// initialize the thread local default heap
|
||||||
// (this will call `_mi_heap_set_default_direct` and thus set the
|
// (this will call `_mi_heap_set_default_direct` and thus set the
|
||||||
// fiber/pthread key to a non-zero value, ensuring `_mi_thread_done` is called)
|
// fiber/pthread key to a non-zero value, ensuring `_mi_thread_done` is called)
|
||||||
if (_mi_heap_init()) return; // returns true if already initialized
|
if (_mi_thread_heap_init()) return; // returns true if already initialized
|
||||||
|
|
||||||
_mi_stat_increase(&_mi_stats_main.threads, 1);
|
_mi_stat_increase(&_mi_stats_main.threads, 1);
|
||||||
mi_atomic_increment_relaxed(&thread_count);
|
mi_atomic_increment_relaxed(&thread_count);
|
||||||
|
@ -450,7 +449,7 @@ void _mi_thread_done(mi_heap_t* heap)
|
||||||
if (heap->thread_id != _mi_thread_id()) return;
|
if (heap->thread_id != _mi_thread_id()) return;
|
||||||
|
|
||||||
// abandon the thread local heap
|
// abandon the thread local heap
|
||||||
if (_mi_heap_done(heap)) return; // returns true if already ran
|
if (_mi_thread_heap_done(heap)) return; // returns true if already ran
|
||||||
}
|
}
|
||||||
|
|
||||||
void _mi_heap_set_default_direct(mi_heap_t* heap) {
|
void _mi_heap_set_default_direct(mi_heap_t* heap) {
|
||||||
|
|
Loading…
Add table
Reference in a new issue