Skip to content

Commit 222601b

Browse files
committed
Use the upstream cursor API to visit abandoned segments
1 parent f81e6c2 commit 222601b

5 files changed

Lines changed: 27 additions & 45 deletions

File tree

‎Include/internal/mimalloc/mimalloc/internal.h‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,6 @@ void _mi_abandoned_reclaim_all(mi_heap_t* heap, mi_segments_tld_t* tld);
249249
void _mi_abandoned_collect(mi_heap_t* heap, bool force, mi_segments_tld_t* tld);
250250
bool _mi_segment_attempt_reclaim(mi_heap_t* heap, mi_segment_t* segment);
251251
bool _mi_segment_visit_blocks(mi_segment_t* segment, int heap_tag, bool visit_blocks, mi_block_visit_fun* visitor, void* arg);
252-
bool _mi_abandoned_visit_blocks_unlocked(mi_subproc_t* subproc, int heap_tag, bool visit_blocks, mi_block_visit_fun* visitor, void* arg); // CPython
253252

254253
// "page.c"
255254
void* _mi_malloc_generic(mi_heap_t* heap, size_t size, bool zero, size_t huge_alignment, mi_page_t** ppage) mi_attr_noexcept mi_attr_malloc;

‎Include/internal/pycore_mimalloc.h‎

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,27 @@ struct _mimalloc_thread_state {
6666
int initialized;
6767
struct llist_node page_list;
6868
};
69+
70+
// Visit the blocks in the abandoned segments (from exited threads) of a
71+
// mimalloc sub-process. Same as mi_abandoned_visit_blocks() but without
72+
// requiring mi_option_visit_abandoned: the caller must guarantee that no
73+
// other thread abandons or reclaims segments concurrently (STW).
74+
static inline bool
75+
_PyMem_mi_visit_abandoned_blocks(mi_subproc_t *subproc, int heap_tag,
76+
bool visit_blocks,
77+
mi_block_visit_fun *visitor, void *arg)
78+
{
79+
mi_arena_field_cursor_t current;
80+
_mi_arena_field_cursor_init(NULL, subproc, true /* visit all */, &current);
81+
mi_segment_t *segment;
82+
bool ok = true;
83+
while (ok && (segment = _mi_arena_segment_clear_abandoned_next(&current)) != NULL) {
84+
ok = _mi_segment_visit_blocks(segment, heap_tag, visit_blocks, visitor, arg);
85+
_mi_arena_segment_mark_abandoned(segment);
86+
}
87+
_mi_arena_field_cursor_done(&current);
88+
return ok;
89+
}
6990
#endif
7091

7192
#endif // Py_INTERNAL_MIMALLOC_H

‎Objects/mimalloc/arena-abandon.c‎

Lines changed: 0 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -345,41 +345,3 @@ bool mi_abandoned_visit_blocks(mi_subproc_id_t subproc_id, int heap_tag, bool vi
345345
return ok;
346346
}
347347

348-
349-
/* -----------------------------------------------------------
350-
CPython: visit all abandoned segments of a sub-process without
351-
taking any locks or claiming the segments.
352-
353-
Unlike `mi_abandoned_visit_blocks`, this does not require
354-
`mi_option_visit_abandoned` to be enabled. The caller must
355-
guarantee that no other thread abandons or reclaims segments
356-
concurrently (in CPython: a stop-the-world pause), and the
357-
visitor must not allocate or free mimalloc managed memory.
358-
----------------------------------------------------------- */
359-
360-
bool _mi_abandoned_visit_blocks_unlocked(mi_subproc_t* subproc, int heap_tag, bool visit_blocks, mi_block_visit_fun* visitor, void* arg) {
361-
// segments in arenas are tracked in the `blocks_abandoned` bitmaps
362-
const size_t max_arena = mi_arena_get_count();
363-
for (size_t arena_idx = 0; arena_idx < max_arena; arena_idx++) {
364-
mi_arena_t* arena = mi_arena_from_index(arena_idx);
365-
if (arena == NULL) continue;
366-
for (size_t field_idx = 0; field_idx < arena->field_count; field_idx++) {
367-
size_t field = mi_atomic_load_relaxed(&arena->blocks_abandoned[field_idx]);
368-
while (field != 0) {
369-
const size_t bit_idx = mi_ctz(field);
370-
field &= ~((size_t)1 << bit_idx);
371-
const mi_bitmap_index_t bitmap_idx = mi_bitmap_index_create(field_idx, bit_idx);
372-
mi_segment_t* const segment = (mi_segment_t*)mi_arena_block_start(arena, bitmap_idx);
373-
mi_assert_internal(mi_atomic_load_relaxed(&segment->thread_id) == 0);
374-
if (segment->subproc != subproc) continue;
375-
if (!_mi_segment_visit_blocks(segment, heap_tag, visit_blocks, visitor, arg)) return false;
376-
}
377-
}
378-
}
379-
// segments outside arenas (OS allocated) are kept in a per sub-process list
380-
for (mi_segment_t* segment = subproc->abandoned_os_list; segment != NULL; segment = segment->abandoned_os_next) {
381-
mi_assert_internal(segment->subproc == subproc);
382-
if (!_mi_segment_visit_blocks(segment, heap_tag, visit_blocks, visitor, arg)) return false;
383-
}
384-
return true;
385-
}

‎Objects/obmalloc.c‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1825,8 +1825,8 @@ get_mimalloc_allocated_blocks(PyInterpreterState *interp)
18251825

18261826
mi_subproc_t *subproc = interp->mimalloc.subproc;
18271827
for (int tag = 0; tag < _Py_MIMALLOC_HEAP_COUNT; tag++) {
1828-
_mi_abandoned_visit_blocks_unlocked(subproc, tag, false, &count_blocks,
1829-
&allocated_blocks);
1828+
_PyMem_mi_visit_abandoned_blocks(subproc, tag, false, &count_blocks,
1829+
&allocated_blocks);
18301830
}
18311831
#else
18321832
// TODO(sgross): this only counts the current thread's blocks.

‎Python/gc_free_threading.c‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -403,13 +403,13 @@ gc_visit_heaps_lock_held(PyInterpreterState *interp, mi_block_visit_fun *visitor
403403
// per-interpreter mimalloc sub-process.
404404
mi_subproc_t *subproc = interp->mimalloc.subproc;
405405
arg->offset = offset_base;
406-
if (!_mi_abandoned_visit_blocks_unlocked(subproc, _Py_MIMALLOC_HEAP_GC,
407-
true, visitor, arg)) {
406+
if (!_PyMem_mi_visit_abandoned_blocks(subproc, _Py_MIMALLOC_HEAP_GC,
407+
true, visitor, arg)) {
408408
return -1;
409409
}
410410
arg->offset = offset_pre;
411-
if (!_mi_abandoned_visit_blocks_unlocked(subproc, _Py_MIMALLOC_HEAP_GC_PRE,
412-
true, visitor, arg)) {
411+
if (!_PyMem_mi_visit_abandoned_blocks(subproc, _Py_MIMALLOC_HEAP_GC_PRE,
412+
true, visitor, arg)) {
413413
return -1;
414414
}
415415
return 0;

0 commit comments

Comments
 (0)