35#ifndef _UTILS_STOREDBITSET_HXX_
36#define _UTILS_STOREDBITSET_HXX_
59 virtual bool get_bit(
unsigned offset) = 0;
69 unsigned offset,
unsigned size,
unsigned value) = 0;
81 virtual unsigned size() = 0;
96 auto* shadow_ptr =
shadow_ + (offset >> 5);
97 auto bit = (UINT32_C(1) << (offset & 31));
99 if (__atomic_fetch_or(shadow_ptr, bit, __ATOMIC_SEQ_CST) & bit) {
103 if ((__atomic_fetch_and(shadow_ptr, ~bit, __ATOMIC_SEQ_CST) & bit) == 0) {
108 __atomic_fetch_or(
dirty_ + (d >> 5), UINT32_C(1) << (d & 31), __ATOMIC_SEQ_CST);
115 return shadow_[offset >> 5] & (UINT32_C(1) << (offset & 31));
119 unsigned offset,
unsigned size,
unsigned value)
override {
126 unsigned sidx = offset >> 5;
127 uint32_t smask = UINT32_C(0xFFFFFFFF);
128 smask >>= (32 -
size);
129 smask <<= (offset & 31);
130 uint32_t sval = value;
131 sval <<= (offset & 31);
132 int rollover =
size + (offset & 31) - 32;
134 uint32_t smask2 = (UINT32_C(1) << rollover) - 1;
135 uint32_t sval2 = value >> (
size - rollover);
137 uint32_t old1 =
shadow_[sidx], new1, old2 =
shadow_[sidx + 1], new2;
140 new1 = (old1 & ~smask) | sval;
141 new2 = (old2 & ~smask2) | sval2;
142 }
while (!__atomic_compare_exchange_n(
shadow_ + sidx, &old1, new1,
143 false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) ||
144 !__atomic_compare_exchange_n(
shadow_ + sidx + 1, &old2, new2,
145 false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST));
150 uint32_t old1 =
shadow_[sidx], new1;
153 new1 = (old1 & ~smask) | sval;
154 }
while (!__atomic_compare_exchange_n(
shadow_ + sidx, &old1, new1,
155 false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST));
162 if (de > highestDirty_) highestDirty_ = de;
164 __atomic_fetch_or(
dirty_ + (d >> 5),(UINT32_C(1)<<(d & 31)), __ATOMIC_SEQ_CST);
174 unsigned val =
shadow_[offset >> 5] >> (offset & 31);
175 int rollover =
size + (offset & 31) - 32;
177 val |=
shadow_[(offset >> 5) + 1] << (
size - rollover);
180 val &= (UINT32_C(1) <<
size) - 1;
200 unsigned ssize = (
size + 31) >> 5;
203 unsigned dsize = (
num_cells() + 31) >> 5;
204 dirty_ =
new uint32_t[dsize];
205 memset(
dirty_, 0, dsize * 4);
230 bool fresh_dirty =
false;
240 unsigned bit_ofs = 0;
245 while (((UINT32_C(1)<<bit_ofs) &
dirty_[dirty_idx]) == 0) {
256 dirty_[cell >> 5] &= ~(UINT32_C(1)<<(cell & 31));
266 return dirty_[cell >>5] & (UINT32_C(1)<<(cell & 31));
289 }
while (!__atomic_compare_exchange_n(&
lowestDirty_, &old_val, d,
false,
290 __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST));
291 old_val = highestDirty_;
296 }
while (!__atomic_compare_exchange_n(&highestDirty_, &old_val, d,
297 false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST));
See OSMutexLock in os/OS.hxx.
Lightweight locking class for protecting small critical sections.
cell_offs_t lowestDirty_
Helper values for iterating over the dirty bits.
ShadowedStoredBitSet(unsigned size, uint8_t granularity)
uint32_t * shadow_
Data of the actual bits. length is size_ / 32 rounded up.
StoredBitSet & set_multi(unsigned offset, unsigned size, unsigned value) override
Sets a block of consecutive bits.
bool is_dirty(cell_offs_t cell)
StoredBitSet & set_bit(unsigned offset, bool value) override
Sets an individual bit to a specific value.
uint32_t * dirty_
Bit set telling whether the individual cells are dirty or not (i.e.
unsigned dirty_size_uint32()
unsigned bit_offs_t
Type indexing all bits.
void clear_dirty(cell_offs_t cell)
Clears the dirty bit for a given cell.
const unsigned size_
Total number of bits.
const uint8_t granularity_
How many bits per cell.
unsigned get_multi(unsigned offset, unsigned size) override
Returns a block of consecutive bits as an integer value.
void update_dirty_bounds(cell_offs_t d)
updates lowestDirty_ and highestDirty_ for a given cell.
void lock_and_flush() override
Grabs a lock and writes the current values to persistent storage.
bool get_bit(unsigned offset) override
Retrieves an individual bit.
uint8_t cell_offs_t
Type indexing cells. Must be an unsigned type.
Abstract class for representing a set of numbered bits that are stored persistently in some backing s...
virtual void flush()=0
Writes the current values to persistent storage.
virtual unsigned get_multi(unsigned offset, unsigned size)=0
Returns a block of consecutive bits as an integer value.
virtual bool get_bit(unsigned offset)=0
Retrieves an individual bit.
virtual StoredBitSet & set_multi(unsigned offset, unsigned size, unsigned value)=0
Sets a block of consecutive bits.
virtual void lock_and_flush()=0
Grabs a lock and writes the current values to persistent storage.
virtual unsigned size()=0
virtual StoredBitSet & set_bit(unsigned offset, bool value)=0
Sets an individual bit to a specific value.
#define HASSERT(x)
Checks that the value of expression x is true, else terminates the current process.