summaryrefslogtreecommitdiffstats
path: root/Objects/mimalloc/segment.c
diff options
context:
space:
mode:
authorSam Gross <colesbury@gmail.com>2024-01-05 20:08:50 (GMT)
committerGitHub <noreply@github.com>2024-01-05 20:08:50 (GMT)
commit0b7476080b58ea2ee71c6c1229994a3bb62fe4fa (patch)
tree75b3715234152987c28c3a6f9879f45029dc43ef /Objects/mimalloc/segment.c
parenteb53750757062255b1793969ca4cb12ef82b91c6 (diff)
downloadcpython-0b7476080b58ea2ee71c6c1229994a3bb62fe4fa.zip
cpython-0b7476080b58ea2ee71c6c1229994a3bb62fe4fa.tar.gz
cpython-0b7476080b58ea2ee71c6c1229994a3bb62fe4fa.tar.bz2
gh-112532: Tag mimalloc heaps and pages (#113742)
* gh-112532: Tag mimalloc heaps and pages Mimalloc pages are data structures that contain contiguous allocations of the same block size. Note that they are distinct from operating system pages. Mimalloc pages are contained in segments. When a thread exits, it abandons any segments and contained pages that have live allocations. These segments and pages may be later reclaimed by another thread. To support GC and certain thread-safety guarantees in free-threaded builds, we want pages to only be reclaimed by the corresponding heap in the claimant thread. For example, we want pages containing GC objects to only be claimed by GC heaps. This allows heaps and pages to be tagged with an integer tag that is used to ensure that abandoned pages are only claimed by heaps with the same tag. Heaps can be initialized with a tag (0-15); any page allocated by that heap copies the corresponding tag. * Fix conversion warning
Diffstat (limited to 'Objects/mimalloc/segment.c')
-rw-r--r--Objects/mimalloc/segment.c20
1 files changed, 17 insertions, 3 deletions
diff --git a/Objects/mimalloc/segment.c b/Objects/mimalloc/segment.c
index 1040da0..d9b39b0 100644
--- a/Objects/mimalloc/segment.c
+++ b/Objects/mimalloc/segment.c
@@ -1299,6 +1299,18 @@ static bool mi_segment_check_free(mi_segment_t* segment, size_t slices_needed, s
return has_page;
}
+static mi_heap_t* mi_heap_by_tag(mi_heap_t* heap, uint8_t tag) {
+ if (heap->tag == tag) {
+ return heap;
+ }
+ for (mi_heap_t *curr = heap->tld->heaps; curr != NULL; curr = curr->next) {
+ if (curr->tag == tag) {
+ return curr;
+ }
+ }
+ return NULL;
+}
+
// Reclaim an abandoned segment; returns NULL if the segment was freed
// set `right_page_reclaimed` to `true` if it reclaimed a page of the right `block_size` that was not full.
static mi_segment_t* mi_segment_reclaim(mi_segment_t* segment, mi_heap_t* heap, size_t requested_block_size, bool* right_page_reclaimed, mi_segments_tld_t* tld) {
@@ -1321,6 +1333,7 @@ static mi_segment_t* mi_segment_reclaim(mi_segment_t* segment, mi_heap_t* heap,
if (mi_slice_is_used(slice)) {
// in use: reclaim the page in our heap
mi_page_t* page = mi_slice_to_page(slice);
+ mi_heap_t* target_heap = mi_heap_by_tag(heap, page->tag);
mi_assert_internal(page->is_committed);
mi_assert_internal(mi_page_thread_free_flag(page)==MI_NEVER_DELAYED_FREE);
mi_assert_internal(mi_page_heap(page) == NULL);
@@ -1328,7 +1341,7 @@ static mi_segment_t* mi_segment_reclaim(mi_segment_t* segment, mi_heap_t* heap,
_mi_stat_decrease(&tld->stats->pages_abandoned, 1);
segment->abandoned--;
// set the heap again and allow delayed free again
- mi_page_set_heap(page, heap);
+ mi_page_set_heap(page, target_heap);
_mi_page_use_delayed_free(page, MI_USE_DELAYED_FREE, true); // override never (after heap is set)
_mi_page_free_collect(page, false); // ensure used count is up to date
if (mi_page_all_free(page)) {
@@ -1337,8 +1350,9 @@ static mi_segment_t* mi_segment_reclaim(mi_segment_t* segment, mi_heap_t* heap,
}
else {
// otherwise reclaim it into the heap
- _mi_page_reclaim(heap, page);
- if (requested_block_size == page->xblock_size && mi_page_has_any_available(page)) {
+ _mi_page_reclaim(target_heap, page);
+ if (requested_block_size == page->xblock_size && mi_page_has_any_available(page) &&
+ heap == target_heap) {
if (right_page_reclaimed != NULL) { *right_page_reclaimed = true; }
}
}