Skip to content

Commit e3ebebb

Browse files
committed
update lock primitive; fix arena exclusive allocation
1 parent 93e1434 commit e3ebebb

File tree

4 files changed

+49
-35
lines changed

4 files changed

+49
-35
lines changed

include/mimalloc/atomic.h

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/* ----------------------------------------------------------------------------
2-
Copyright (c) 2018-2023 Microsoft Research, Daan Leijen
2+
Copyright (c) 2018-2024 Microsoft Research, Daan Leijen
33
This is free software; you can redistribute it and/or modify it under the
44
terms of the MIT license. A copy of the license can be found in the file
55
"LICENSE" at the root of this distribution.
@@ -411,8 +411,11 @@ static inline void mi_atomic_yield(void) {
411411
#pragma warning(disable:26110) // unlock with holding lock
412412
#endif
413413

414+
#define mi_lock(lock) for(bool _go = (mi_lock_acquire(lock),true); _go; (mi_lock_release(lock), _go=false) )
415+
414416
#if defined(_WIN32)
415417

418+
#if 1
416419
#define mi_lock_t SRWLOCK // slim reader-writer lock
417420

418421
static inline bool mi_lock_try_acquire(mi_lock_t* lock) {
@@ -432,6 +435,30 @@ static inline void mi_lock_done(mi_lock_t* lock) {
432435
// nothing
433436
}
434437

438+
#else
439+
#define mi_lock_t CRITICAL_SECTION
440+
441+
static inline bool mi_lock_try_acquire(mi_lock_t* lock) {
442+
return TryEnterCriticalSection(lock);
443+
444+
}
445+
static inline void mi_lock_acquire(mi_lock_t* lock) {
446+
EnterCriticalSection(lock);
447+
448+
}
449+
static inline void mi_lock_release(mi_lock_t* lock) {
450+
LeaveCriticalSection(lock);
451+
452+
}
453+
static inline void mi_lock_init(mi_lock_t* lock) {
454+
InitializeCriticalSection(lock);
455+
456+
}
457+
static inline void mi_lock_done(mi_lock_t* lock) {
458+
DeleteCriticalSection(lock);
459+
460+
}
461+
#endif
435462

436463
#elif defined(MI_USE_PTHREADS)
437464

@@ -506,6 +533,4 @@ static inline void mi_lock_done(mi_lock_t* lock) {
506533
#endif
507534

508535

509-
510-
511536
#endif // __MIMALLOC_ATOMIC_H

src/arena-abandon.c

Lines changed: 11 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -120,11 +120,7 @@ static void mi_arena_segment_os_mark_abandoned(mi_segment_t* segment) {
120120
mi_assert(segment->memid.memkind != MI_MEM_ARENA);
121121
// not in an arena; we use a list of abandoned segments
122122
mi_subproc_t* const subproc = segment->subproc;
123-
if (!mi_lock_acquire(&subproc->abandoned_os_lock)) {
124-
_mi_error_message(EFAULT, "internal error: failed to acquire the abandoned (os) segment lock to mark abandonment");
125-
// we can continue but cannot visit/reclaim such blocks..
126-
}
127-
else {
123+
mi_lock(&subproc->abandoned_os_lock) {
128124
// push on the tail of the list (important for the visitor)
129125
mi_segment_t* prev = subproc->abandoned_os_list_tail;
130126
mi_assert_internal(prev == NULL || prev->abandoned_os_next == NULL);
@@ -138,7 +134,6 @@ static void mi_arena_segment_os_mark_abandoned(mi_segment_t* segment) {
138134
mi_atomic_increment_relaxed(&subproc->abandoned_os_list_count);
139135
mi_atomic_increment_relaxed(&subproc->abandoned_count);
140136
// and release the lock
141-
mi_lock_release(&subproc->abandoned_os_lock);
142137
}
143138
return;
144139
}
@@ -251,7 +246,7 @@ static mi_segment_t* mi_arena_segment_clear_abandoned_next_field(mi_arena_field_
251246
if mi_unlikely(field != 0) { // skip zero fields quickly
252247
// we only take the arena lock if there are actually abandoned segments present
253248
if (!has_lock && mi_option_is_enabled(mi_option_visit_abandoned)) {
254-
has_lock = (previous->visit_all ? mi_lock_acquire(&arena->abandoned_visit_lock) : mi_lock_try_acquire(&arena->abandoned_visit_lock));
249+
has_lock = (previous->visit_all ? (mi_lock_acquire(&arena->abandoned_visit_lock),true) : mi_lock_try_acquire(&arena->abandoned_visit_lock));
255250
if (!has_lock) {
256251
if (previous->visit_all) {
257252
_mi_error_message(EFAULT, "internal error: failed to visit all abandoned segments due to failure to acquire the visitor lock");
@@ -289,8 +284,8 @@ static mi_segment_t* mi_arena_segment_clear_abandoned_next_list(mi_arena_field_c
289284
// we only allow one thread per sub-process to do to visit guarded by the `abandoned_os_visit_lock`.
290285
// The lock is released when the cursor is released.
291286
if (!previous->hold_visit_lock) {
292-
previous->hold_visit_lock = (previous->visit_all ? mi_lock_acquire(&previous->subproc->abandoned_os_visit_lock)
293-
: mi_lock_try_acquire(&previous->subproc->abandoned_os_visit_lock));
287+
previous->hold_visit_lock = (previous->visit_all ? (mi_lock_acquire(&previous->subproc->abandoned_os_visit_lock),true)
288+
: mi_lock_try_acquire(&previous->subproc->abandoned_os_visit_lock));
294289
if (!previous->hold_visit_lock) {
295290
if (previous->visit_all) {
296291
_mi_error_message(EFAULT, "internal error: failed to visit all abandoned segments due to failure to acquire the OS visitor lock");
@@ -301,21 +296,15 @@ static mi_segment_t* mi_arena_segment_clear_abandoned_next_list(mi_arena_field_c
301296
// One list entry at a time
302297
while (previous->os_list_count > 0) {
303298
previous->os_list_count--;
304-
const bool has_lock = mi_lock_acquire(&previous->subproc->abandoned_os_lock); // this could contend with concurrent OS block abandonment and reclaim from `free`
305-
if (has_lock) {
306-
mi_segment_t* segment = previous->subproc->abandoned_os_list;
307-
// pop from head of the list, a subsequent mark will push at the end (and thus we iterate through os_list_count entries)
308-
if (segment == NULL || mi_arena_segment_os_clear_abandoned(segment, false /* we already have the lock */)) {
309-
mi_lock_release(&previous->subproc->abandoned_os_lock);
310-
return segment;
311-
}
312-
// already abandoned, try again
299+
mi_lock_acquire(&previous->subproc->abandoned_os_lock); // this could contend with concurrent OS block abandonment and reclaim from `free`
300+
mi_segment_t* segment = previous->subproc->abandoned_os_list;
301+
// pop from head of the list, a subsequent mark will push at the end (and thus we iterate through os_list_count entries)
302+
if (segment == NULL || mi_arena_segment_os_clear_abandoned(segment, false /* we already have the lock */)) {
313303
mi_lock_release(&previous->subproc->abandoned_os_lock);
304+
return segment;
314305
}
315-
else {
316-
_mi_error_message(EFAULT, "failed to acquire abandoned OS list lock during abandoned block visit\n");
317-
return NULL;
318-
}
306+
// already abandoned, try again
307+
mi_lock_release(&previous->subproc->abandoned_os_lock);
319308
}
320309
// done
321310
mi_assert_internal(previous->os_list_count == 0);

src/arena.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -394,8 +394,9 @@ void* _mi_arena_alloc_aligned(size_t size, size_t alignment, size_t align_offset
394394
const int numa_node = _mi_os_numa_node(); // current numa node
395395

396396
// try to allocate in an arena if the alignment is small enough and the object is not too small (as for heap meta data)
397-
if (!mi_option_is_enabled(mi_option_disallow_arena_alloc) || req_arena_id != _mi_arena_id_none()) { // is arena allocation allowed?
398-
if (size >= MI_ARENA_MIN_OBJ_SIZE && alignment <= MI_SEGMENT_ALIGN && align_offset == 0) {
397+
if (!mi_option_is_enabled(mi_option_disallow_arena_alloc)) { // is arena allocation allowed?
398+
if (size >= MI_ARENA_MIN_OBJ_SIZE && alignment <= MI_SEGMENT_ALIGN && align_offset == 0)
399+
{
399400
void* p = mi_arena_try_alloc(numa_node, size, alignment, commit, allow_large, req_arena_id, memid);
400401
if (p != NULL) return p;
401402

src/init.c

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -168,8 +168,8 @@ mi_stats_t _mi_stats_main = { MI_STATS_NULL };
168168
#if MI_GUARDED
169169
mi_decl_export void mi_heap_guarded_set_sample_rate(mi_heap_t* heap, size_t sample_rate, size_t seed) {
170170
heap->guarded_sample_seed = seed;
171-
if (heap->guarded_sample_seed == 0) {
172-
heap->guarded_sample_seed = _mi_heap_random_next(heap);
171+
if (heap->guarded_sample_seed == 0) {
172+
heap->guarded_sample_seed = _mi_heap_random_next(heap);
173173
}
174174
heap->guarded_sample_rate = sample_rate;
175175
if (heap->guarded_sample_rate >= 1) {
@@ -187,9 +187,9 @@ void _mi_heap_guarded_init(mi_heap_t* heap) {
187187
mi_heap_guarded_set_sample_rate(heap,
188188
(size_t)mi_option_get_clamp(mi_option_guarded_sample_rate, 0, LONG_MAX),
189189
(size_t)mi_option_get(mi_option_guarded_sample_seed));
190-
mi_heap_guarded_set_size_bound(heap,
190+
mi_heap_guarded_set_size_bound(heap,
191191
(size_t)mi_option_get_clamp(mi_option_guarded_min, 0, LONG_MAX),
192-
(size_t)mi_option_get_clamp(mi_option_guarded_max, 0, LONG_MAX) );
192+
(size_t)mi_option_get_clamp(mi_option_guarded_max, 0, LONG_MAX) );
193193
}
194194
#else
195195
mi_decl_export void mi_heap_guarded_set_sample_rate(mi_heap_t* heap, size_t sample_rate, size_t seed) {
@@ -257,11 +257,10 @@ void mi_subproc_delete(mi_subproc_id_t subproc_id) {
257257
mi_subproc_t* subproc = _mi_subproc_from_id(subproc_id);
258258
// check if there are no abandoned segments still..
259259
bool safe_to_delete = false;
260-
if (mi_lock_acquire(&subproc->abandoned_os_lock)) {
260+
mi_lock(&subproc->abandoned_os_lock) {
261261
if (subproc->abandoned_os_list == NULL) {
262262
safe_to_delete = true;
263263
}
264-
mi_lock_release(&subproc->abandoned_os_lock);
265264
}
266265
if (!safe_to_delete) return;
267266
// safe to release
@@ -398,7 +397,7 @@ void _mi_tld_init(mi_tld_t* tld, mi_heap_t* bheap) {
398397
tld->heap_backing = bheap;
399398
tld->heaps = NULL;
400399
tld->segments.subproc = &mi_subproc_default;
401-
tld->segments.stats = &tld->stats;
400+
tld->segments.stats = &tld->stats;
402401
}
403402

404403
// Free the thread local default heap (called from `mi_thread_done`)
@@ -599,7 +598,7 @@ static void mi_detect_cpu_features(void) {
599598
}
600599
#else
601600
static void mi_detect_cpu_features(void) {
602-
// nothing
601+
// nothing
603602
}
604603
#endif
605604

0 commit comments

Comments
 (0)