mirror of
https://github.com/microsoft/mimalloc.git
synced 2025-05-05 23:19:31 +03:00
delete all thread owned heaps when a thread is terminated (issue #202)
This commit is contained in:
parent
946a71c4a9
commit
8a2a52843d
4 changed files with 42 additions and 6 deletions
|
@ -329,6 +329,7 @@ struct mi_heap_s {
|
||||||
uintptr_t keys[2]; // two random keys used to encode the `thread_delayed_free` list
|
uintptr_t keys[2]; // two random keys used to encode the `thread_delayed_free` list
|
||||||
mi_random_ctx_t random; // random number context used for secure allocation
|
mi_random_ctx_t random; // random number context used for secure allocation
|
||||||
size_t page_count; // total number of pages in the `pages` queues.
|
size_t page_count; // total number of pages in the `pages` queues.
|
||||||
|
mi_heap_t* next; // list of heaps per thread
|
||||||
bool no_reclaim; // `true` if this heap should not reclaim abandoned pages
|
bool no_reclaim; // `true` if this heap should not reclaim abandoned pages
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -469,6 +470,7 @@ struct mi_tld_s {
|
||||||
unsigned long long heartbeat; // monotonic heartbeat count
|
unsigned long long heartbeat; // monotonic heartbeat count
|
||||||
bool recurse; // true if deferred was called; used to prevent infinite recursion.
|
bool recurse; // true if deferred was called; used to prevent infinite recursion.
|
||||||
mi_heap_t* heap_backing; // backing heap of this thread (cannot be deleted)
|
mi_heap_t* heap_backing; // backing heap of this thread (cannot be deleted)
|
||||||
|
mi_heap_t* heaps; // list of heaps in this thread (so we can abandon all when the thread terminates)
|
||||||
mi_segments_tld_t segments; // segment tld
|
mi_segments_tld_t segments; // segment tld
|
||||||
mi_os_tld_t os; // os tld
|
mi_os_tld_t os; // os tld
|
||||||
mi_stats_t stats; // statistics
|
mi_stats_t stats; // statistics
|
||||||
|
|
21
src/heap.c
21
src/heap.c
|
@ -191,7 +191,7 @@ mi_heap_t* mi_heap_get_backing(void) {
|
||||||
|
|
||||||
mi_heap_t* mi_heap_new(void) {
|
mi_heap_t* mi_heap_new(void) {
|
||||||
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);
|
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;
|
||||||
memcpy(heap, &_mi_heap_empty, sizeof(mi_heap_t));
|
memcpy(heap, &_mi_heap_empty, sizeof(mi_heap_t));
|
||||||
heap->tld = bheap->tld;
|
heap->tld = bheap->tld;
|
||||||
|
@ -201,6 +201,9 @@ mi_heap_t* mi_heap_new(void) {
|
||||||
heap->keys[0] = _mi_heap_random_next(heap);
|
heap->keys[0] = _mi_heap_random_next(heap);
|
||||||
heap->keys[1] = _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
|
heap->no_reclaim = true; // don't reclaim abandoned pages or otherwise destroy is unsafe
|
||||||
|
// push on the thread local heaps list
|
||||||
|
heap->next = heap->tld->heaps;
|
||||||
|
heap->tld->heaps = heap;
|
||||||
return heap;
|
return heap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -230,6 +233,22 @@ static void mi_heap_free(mi_heap_t* heap) {
|
||||||
if (mi_heap_is_default(heap)) {
|
if (mi_heap_is_default(heap)) {
|
||||||
_mi_heap_set_default_direct(heap->tld->heap_backing);
|
_mi_heap_set_default_direct(heap->tld->heap_backing);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// remove ourselves from the thread local heaps list
|
||||||
|
// linear search but we expect the number of heaps to be relatively small
|
||||||
|
mi_heap_t* prev = NULL;
|
||||||
|
mi_heap_t* curr = heap->tld->heaps;
|
||||||
|
while (curr != heap && curr != NULL) {
|
||||||
|
prev = curr;
|
||||||
|
curr = curr->next;
|
||||||
|
}
|
||||||
|
mi_assert_internal(curr == heap);
|
||||||
|
if (curr == heap) {
|
||||||
|
if (prev != NULL) { prev->next = heap->next; }
|
||||||
|
else { heap->tld->heaps = heap->next; }
|
||||||
|
}
|
||||||
|
mi_assert_internal(heap->tld->heaps != NULL);
|
||||||
|
|
||||||
// and free the used memory
|
// and free the used memory
|
||||||
mi_free(heap);
|
mi_free(heap);
|
||||||
}
|
}
|
||||||
|
|
23
src/init.c
23
src/init.c
|
@ -97,6 +97,7 @@ const mi_heap_t _mi_heap_empty = {
|
||||||
{ 0, 0 }, // keys
|
{ 0, 0 }, // keys
|
||||||
{ {0}, {0}, 0 },
|
{ {0}, {0}, 0 },
|
||||||
0, // page count
|
0, // page count
|
||||||
|
NULL, // next
|
||||||
false
|
false
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -111,7 +112,7 @@ extern mi_heap_t _mi_heap_main;
|
||||||
|
|
||||||
static mi_tld_t tld_main = {
|
static mi_tld_t tld_main = {
|
||||||
0, false,
|
0, false,
|
||||||
&_mi_heap_main,
|
&_mi_heap_main, &_mi_heap_main,
|
||||||
{ { NULL, NULL }, {NULL ,NULL}, {NULL ,NULL, 0},
|
{ { NULL, NULL }, {NULL ,NULL}, {NULL ,NULL, 0},
|
||||||
0, 0, 0, 0, 0, 0, NULL,
|
0, 0, 0, 0, 0, 0, NULL,
|
||||||
tld_main_stats, tld_main_os
|
tld_main_stats, tld_main_os
|
||||||
|
@ -130,6 +131,7 @@ mi_heap_t _mi_heap_main = {
|
||||||
{ 0, 0 }, // the key of the main heap can be fixed (unlike page keys that need to be secure!)
|
{ 0, 0 }, // the key of the main heap can be fixed (unlike page keys that need to be secure!)
|
||||||
{ {0x846ca68b}, {0}, 0 }, // random
|
{ {0x846ca68b}, {0}, 0 }, // random
|
||||||
0, // page count
|
0, // page count
|
||||||
|
NULL, // next heap
|
||||||
false // can reclaim
|
false // can reclaim
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -192,6 +194,7 @@ static bool _mi_heap_init(void) {
|
||||||
heap->keys[1] = _mi_heap_random_next(heap);
|
heap->keys[1] = _mi_heap_random_next(heap);
|
||||||
heap->tld = tld;
|
heap->tld = tld;
|
||||||
tld->heap_backing = heap;
|
tld->heap_backing = heap;
|
||||||
|
tld->heaps = heap;
|
||||||
tld->segments.stats = &tld->stats;
|
tld->segments.stats = &tld->stats;
|
||||||
tld->segments.os = &tld->os;
|
tld->segments.os = &tld->os;
|
||||||
tld->os.stats = &tld->stats;
|
tld->os.stats = &tld->stats;
|
||||||
|
@ -207,12 +210,24 @@ static bool _mi_heap_done(mi_heap_t* heap) {
|
||||||
// reset default heap
|
// reset default heap
|
||||||
_mi_heap_set_default_direct(_mi_is_main_thread() ? &_mi_heap_main : (mi_heap_t*)&_mi_heap_empty);
|
_mi_heap_set_default_direct(_mi_is_main_thread() ? &_mi_heap_main : (mi_heap_t*)&_mi_heap_empty);
|
||||||
|
|
||||||
// todo: delete all non-backing heaps?
|
// switch to backing heap
|
||||||
|
|
||||||
// switch to backing heap and free it
|
|
||||||
heap = heap->tld->heap_backing;
|
heap = heap->tld->heap_backing;
|
||||||
if (!mi_heap_is_initialized(heap)) return false;
|
if (!mi_heap_is_initialized(heap)) return false;
|
||||||
|
|
||||||
|
|
||||||
|
// delete all non-backing heaps in this thread
|
||||||
|
mi_heap_t* curr = heap->tld->heaps;
|
||||||
|
while (curr != NULL) {
|
||||||
|
mi_heap_t* next = curr->next; // save `next` as `curr` will be freed
|
||||||
|
if (curr != heap) {
|
||||||
|
mi_assert_internal(!mi_heap_is_backing(curr));
|
||||||
|
mi_heap_delete(curr);
|
||||||
|
}
|
||||||
|
curr = next;
|
||||||
|
}
|
||||||
|
mi_assert_internal(heap->tld->heaps == heap && heap->next == NULL);
|
||||||
|
mi_assert_internal(mi_heap_is_backing(heap));
|
||||||
|
|
||||||
// collect if not the main thread
|
// collect if not the main thread
|
||||||
if (heap != &_mi_heap_main) {
|
if (heap != &_mi_heap_main) {
|
||||||
_mi_heap_collect_abandon(heap);
|
_mi_heap_collect_abandon(heap);
|
||||||
|
|
|
@ -28,7 +28,7 @@ int main() {
|
||||||
mi_stats_reset(); // ignore earlier allocations
|
mi_stats_reset(); // ignore earlier allocations
|
||||||
// heap_no_delete(); // issue #202
|
// heap_no_delete(); // issue #202
|
||||||
// heap_late_free(); // issue #204
|
// heap_late_free(); // issue #204
|
||||||
various_tests();
|
// various_tests();
|
||||||
mi_stats_print(NULL);
|
mi_stats_print(NULL);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue