Try to atomically claim a sequence of `count` bits in a single field at `idx` in `bitmap`. Returns `true` on success.
| 42 | // Try to atomically claim a sequence of `count` bits in a single |
| 43 | // field at `idx` in `bitmap`. Returns `true` on success. |
| 44 | inline bool _mi_bitmap_try_find_claim_field(mi_bitmap_t bitmap, size_t idx, const size_t count, mi_bitmap_index_t* bitmap_idx) |
| 45 | { |
| 46 | mi_assert_internal(bitmap_idx != NULL); |
| 47 | mi_assert_internal(count <= MI_BITMAP_FIELD_BITS); |
| 48 | mi_assert_internal(count > 0); |
| 49 | mi_bitmap_field_t* field = &bitmap[idx]; |
| 50 | size_t map = mi_atomic_load_relaxed(field); |
| 51 | if (map==MI_BITMAP_FIELD_FULL) return false; // short cut |
| 52 | |
| 53 | // search for 0-bit sequence of length count |
| 54 | const size_t mask = mi_bitmap_mask_(count, 0); |
| 55 | const size_t bitidx_max = MI_BITMAP_FIELD_BITS - count; |
| 56 | |
| 57 | #ifdef MI_HAVE_FAST_BITSCAN |
| 58 | size_t bitidx = mi_ctz(~map); // quickly find the first zero bit if possible |
| 59 | #else |
| 60 | size_t bitidx = 0; // otherwise start at 0 |
| 61 | #endif |
| 62 | size_t m = (mask << bitidx); // invariant: m == mask shifted by bitidx |
| 63 | |
| 64 | // scan linearly for a free range of zero bits |
| 65 | while (bitidx <= bitidx_max) { |
| 66 | const size_t mapm = map & m; |
| 67 | if (mapm == 0) { // are the mask bits free at bitidx? |
| 68 | mi_assert_internal((m >> bitidx) == mask); // no overflow? |
| 69 | const size_t newmap = map | m; |
| 70 | mi_assert_internal((newmap^map) >> bitidx == mask); |
| 71 | if (!mi_atomic_cas_weak_acq_rel(field, &map, newmap)) { // TODO: use strong cas here? |
| 72 | // no success, another thread claimed concurrently.. keep going (with updated `map`) |
| 73 | continue; |
| 74 | } |
| 75 | else { |
| 76 | // success, we claimed the bits! |
| 77 | *bitmap_idx = mi_bitmap_index_create(idx, bitidx); |
| 78 | return true; |
| 79 | } |
| 80 | } |
| 81 | else { |
| 82 | // on to the next bit range |
| 83 | #ifdef MI_HAVE_FAST_BITSCAN |
| 84 | const size_t shift = (count == 1 ? 1 : mi_bsr(mapm) - bitidx + 1); |
| 85 | mi_assert_internal(shift > 0 && shift <= count); |
| 86 | #else |
| 87 | const size_t shift = 1; |
| 88 | #endif |
| 89 | bitidx += shift; |
| 90 | m <<= shift; |
| 91 | } |
| 92 | } |
| 93 | // no bits found |
| 94 | return false; |
| 95 | } |
| 96 | |
| 97 | // Find `count` bits of 0 and set them to 1 atomically; returns `true` on success. |
| 98 | // Starts at idx, and wraps around to search in all `bitmap_fields` fields. |
no test coverage detected