Skip to content

Commit 8b53a14

Browse files
committed
atomically read page_bitmaps
page_bitmaps does not need to be volatile since it is going to be treated as atomic. In fact, as long as each variable is treated as atomic, we do not need volatile at all, as that means it is modified by outside means, aka hardware, etc. The atomic macros already ensure optimizations that could cause incorrect values to be used do not happen. Finally, the first loop is redundant as they are iterated over again in the loop below.
1 parent ee39300 commit 8b53a14

File tree

2 files changed

+32
-39
lines changed

2 files changed

+32
-39
lines changed

src/allocator.c

+29-36
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ DISPATCH_ALWAYS_INLINE_NDEBUG DISPATCH_CONST
211211
static bool
212212
bitmap_is_full(bitmap_t bits)
213213
{
214-
return (bits == BITMAP_ALL_ONES);
214+
return atomic_load_explicit(bits, memory_order_relaxed) == BITMAP_ALL_ONES);
215215
}
216216

217217
#define NO_BITS_WERE_UNSET (UINT_MAX)
@@ -220,7 +220,7 @@ bitmap_is_full(bitmap_t bits)
220220
// allowed to be set.
221221
DISPATCH_ALWAYS_INLINE_NDEBUG
222222
static unsigned int
223-
bitmap_set_first_unset_bit_upto_index(volatile bitmap_t *bitmap,
223+
bitmap_set_first_unset_bit_upto_index(bitmap_t *bitmap,
224224
unsigned int max_index)
225225
{
226226
// No barriers needed in acquire path: the just-allocated
@@ -233,7 +233,7 @@ bitmap_set_first_unset_bit_upto_index(volatile bitmap_t *bitmap,
233233

234234
DISPATCH_ALWAYS_INLINE
235235
static unsigned int
236-
bitmap_set_first_unset_bit(volatile bitmap_t *bitmap)
236+
bitmap_set_first_unset_bit(bitmap_t *bitmap)
237237
{
238238
return bitmap_set_first_unset_bit_upto_index(bitmap, UINT_MAX);
239239
}
@@ -244,7 +244,7 @@ bitmap_set_first_unset_bit(volatile bitmap_t *bitmap)
244244
// Return true if this bit was the last in the bitmap, and it is now all zeroes
245245
DISPATCH_ALWAYS_INLINE_NDEBUG
246246
static bool
247-
bitmap_clear_bit(volatile bitmap_t *bitmap, unsigned int index,
247+
bitmap_clear_bit(bitmap_t *bitmap, unsigned int index,
248248
bool exclusively)
249249
{
250250
#if DISPATCH_DEBUG
@@ -267,8 +267,8 @@ bitmap_clear_bit(volatile bitmap_t *bitmap, unsigned int index,
267267

268268
DISPATCH_ALWAYS_INLINE_NDEBUG
269269
static void
270-
mark_bitmap_as_full_if_still_full(volatile bitmap_t *supermap,
271-
unsigned int bitmap_index, volatile bitmap_t *bitmap)
270+
mark_bitmap_as_full_if_still_full(bitmap_t *supermap,
271+
unsigned int bitmap_index, bitmap_t *bitmap)
272272
{
273273
#if DISPATCH_DEBUG
274274
dispatch_assert(bitmap_index < BITMAPS_PER_SUPERMAP);
@@ -321,12 +321,12 @@ alloc_continuation_from_magazine(struct dispatch_magazine_s *magazine)
321321
unsigned int s, b, index;
322322

323323
for (s = 0; s < SUPERMAPS_PER_MAGAZINE; s++) {
324-
volatile bitmap_t *supermap = supermap_address(magazine, s);
324+
bitmap_t *supermap = supermap_address(magazine, s);
325325
if (bitmap_is_full(*supermap)) {
326326
continue;
327327
}
328328
for (b = 0; b < BITMAPS_PER_SUPERMAP; b++) {
329-
volatile bitmap_t *bitmap = bitmap_address(magazine, s, b);
329+
bitmap_t *bitmap = bitmap_address(magazine, s, b);
330330
index = bitmap_set_first_unset_bit(bitmap);
331331
if (index != NO_BITS_WERE_UNSET) {
332332
set_last_found_page(
@@ -530,44 +530,37 @@ _dispatch_alloc_maybe_madvise_page(dispatch_continuation_t c)
530530
// page can't be madvised; maybe it contains non-continuations
531531
return;
532532
}
533-
// Are all the continuations in this page unallocated?
534-
volatile bitmap_t *page_bitmaps;
533+
534+
bitmap_t *page_bitmaps;
535535
get_maps_and_indices_for_continuation((dispatch_continuation_t)page, NULL,
536-
NULL, (bitmap_t **)&page_bitmaps, NULL);
536+
NULL, &page_bitmaps, NULL);
537537
unsigned int i;
538+
539+
// Try to take ownership of them all, and if it fails, unlock the ones we locked
538540
for (i = 0; i < BITMAPS_PER_PAGE; i++) {
539-
if (page_bitmaps[i] != 0) {
540-
return;
541-
}
542-
}
543-
// They are all unallocated, so we could madvise the page. Try to
544-
// take ownership of them all.
545-
int last_locked = 0;
546-
do {
547-
if (!os_atomic_cmpxchg(&page_bitmaps[last_locked], BITMAP_C(0),
541+
if (!os_atomic_cmpxchg(&page_bitmaps[i], BITMAP_C(0),
548542
BITMAP_ALL_ONES, relaxed)) {
549543
// We didn't get one; since there is a cont allocated in
550544
// the page, we can't madvise. Give up and unlock all.
551-
goto unlock;
545+
break;
552546
}
553-
} while (++last_locked < (signed)BITMAPS_PER_PAGE);
547+
}
548+
549+
if (i >= BITMAPS_PER_PAGE) {
554550
#if DISPATCH_DEBUG
555-
//fprintf(stderr, "%s: madvised page %p for cont %p (next = %p), "
556-
// "[%u+1]=%u bitmaps at %p\n", __func__, page, c, c->do_next,
557-
// last_locked-1, BITMAPS_PER_PAGE, &page_bitmaps[0]);
558-
// Scribble to expose use-after-free bugs
559-
// madvise (syscall) flushes these stores
560-
memset(page, DISPATCH_ALLOCATOR_SCRIBBLE, DISPATCH_ALLOCATOR_PAGE_SIZE);
551+
// fprintf(stderr, "%s: madvised page %p for cont %p (next = %p), "
552+
// "[%u+1]=%u bitmaps at %p\n", __func__, page, c, c->do_next,
553+
// last_locked-1, BITMAPS_PER_PAGE, &page_bitmaps[0]);
554+
// Scribble to expose use-after-free bugs
555+
// madvise (syscall) flushes these stores
556+
memset(page, DISPATCH_ALLOCATOR_SCRIBBLE, DISPATCH_ALLOCATOR_PAGE_SIZE);
561557
#endif
562-
(void)dispatch_assume_zero(madvise(page, DISPATCH_ALLOCATOR_PAGE_SIZE,
563-
MADV_FREE));
564-
565-
unlock:
566-
while (last_locked > 1) {
567-
page_bitmaps[--last_locked] = BITMAP_C(0);
558+
// madvise the page
559+
(void)dispatch_assume_zero(madvise(page, DISPATCH_ALLOCATOR_PAGE_SIZE,
560+
MADV_FREE));
568561
}
569-
if (last_locked) {
570-
os_atomic_store(&page_bitmaps[0], BITMAP_C(0), relaxed);
562+
while (i) {
563+
os_atomic_store(&page_bitmaps[--i], BITMAP_C(0), relaxed);
571564
}
572565
return;
573566
}

src/shims/atomic_sfb.h

+3-3
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
// Returns UINT_MAX if all the bits in p were already set.
3333
DISPATCH_ALWAYS_INLINE
3434
static inline unsigned int
35-
os_atomic_set_first_bit(volatile unsigned long *p, unsigned int max)
35+
os_atomic_set_first_bit(unsigned long *p, unsigned int max)
3636
{
3737
unsigned long val, bit;
3838
if (max > (sizeof(val) * 8)) {
@@ -82,7 +82,7 @@ os_atomic_set_first_bit(volatile unsigned long *p, unsigned int max)
8282

8383
DISPATCH_ALWAYS_INLINE
8484
static inline unsigned int
85-
os_atomic_set_first_bit(volatile unsigned long *p, unsigned int max_index)
85+
os_atomic_set_first_bit(unsigned long *p, unsigned int max)
8686
{
8787
unsigned int index;
8888
unsigned long b, b_masked;
@@ -94,7 +94,7 @@ os_atomic_set_first_bit(volatile unsigned long *p, unsigned int max_index)
9494
os_atomic_rmw_loop_give_up(return UINT_MAX);
9595
}
9696
index--;
97-
if (unlikely(index > max_index)) {
97+
if (unlikely(index > max)) {
9898
os_atomic_rmw_loop_give_up(return UINT_MAX);
9999
}
100100
b_masked = b | (1UL << index);

0 commit comments

Comments
 (0)