Skip to content

Commit a018d3b

Browse files
committed
[eclipse-iceoryx#139] Add and test bitset reset_next
1 parent 1a8e019 commit a018d3b

File tree

3 files changed

+108
-16
lines changed

3 files changed

+108
-16
lines changed

iceoryx2-bb/lock-free/src/mpmc/bit_set.rs

+67-8
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ pub type BitSet = details::BitSet<OwningPointer<BitsetElement>>;
6161
pub type RelocatableBitSet = details::BitSet<RelocatablePointer<BitsetElement>>;
6262

6363
pub mod details {
64+
use std::sync::atomic::AtomicUsize;
65+
6466
use super::*;
6567

6668
#[derive(Debug)]
@@ -69,6 +71,7 @@ pub mod details {
6971
data_ptr: PointerType,
7072
capacity: usize,
7173
array_capacity: usize,
74+
reset_position: AtomicUsize,
7275
is_memory_initialized: AtomicBool,
7376
}
7477

@@ -95,6 +98,7 @@ pub mod details {
9598
capacity,
9699
array_capacity,
97100
is_memory_initialized: AtomicBool::new(true),
101+
reset_position: AtomicUsize::new(0),
98102
}
99103
}
100104
}
@@ -106,6 +110,7 @@ pub mod details {
106110
capacity,
107111
array_capacity: Self::array_capacity(capacity),
108112
is_memory_initialized: AtomicBool::new(false),
113+
reset_position: AtomicUsize::new(0),
109114
}
110115
}
111116

@@ -152,6 +157,7 @@ pub mod details {
152157
capacity,
153158
array_capacity: Self::array_capacity(capacity),
154159
is_memory_initialized: AtomicBool::new(true),
160+
reset_position: AtomicUsize::new(0),
155161
}
156162
}
157163
}
@@ -180,7 +186,10 @@ pub mod details {
180186
);
181187
}
182188

183-
fn set_bit(&self, index: usize, bit: usize) -> bool {
189+
fn set_bit(&self, id: usize) -> bool {
190+
let index = id / BITSET_ELEMENT_BITSIZE;
191+
let bit = id % BITSET_ELEMENT_BITSIZE;
192+
184193
let data_ref = unsafe { &(*self.data_ptr.as_ptr().add(index)) };
185194
let mut current = data_ref.load(Ordering::Relaxed);
186195
let bit = 1 << bit;
@@ -204,7 +213,36 @@ pub mod details {
204213
}
205214
}
206215

216+
fn clear_bit(&self, id: usize) -> bool {
217+
let index = id / BITSET_ELEMENT_BITSIZE;
218+
let bit = id % BITSET_ELEMENT_BITSIZE;
219+
220+
let data_ref = unsafe { &(*self.data_ptr.as_ptr().add(index)) };
221+
let mut current = data_ref.load(Ordering::Relaxed);
222+
let bit = 1 << bit;
223+
224+
loop {
225+
if current & bit == 0 {
226+
return false;
227+
}
228+
229+
let current_with_bit = current & !bit;
230+
231+
match data_ref.compare_exchange(
232+
current,
233+
current_with_bit,
234+
Ordering::Relaxed,
235+
Ordering::Relaxed,
236+
) {
237+
Ok(_) => return true,
238+
Err(v) => current = v,
239+
}
240+
}
241+
}
242+
207243
/// Sets a bit in the BitSet
244+
/// If the bit was successfully set it returns true, if the bit was already set it
245+
/// returns false.
208246
pub fn set(&self, id: usize) -> bool {
209247
self.verify_init("set");
210248
debug_assert!(
@@ -213,14 +251,29 @@ pub mod details {
213251
id
214252
);
215253

216-
let bitset_index = id / BITSET_ELEMENT_BITSIZE;
217-
let bit = id % BITSET_ELEMENT_BITSIZE;
218-
self.set_bit(bitset_index, bit)
254+
self.set_bit(id)
255+
}
256+
257+
/// Resets the next set bit and returns the bit index. If no bit was set it returns
258+
/// [`None`].
259+
pub fn reset_next(&self) -> Option<usize> {
260+
let mut current_position = self.reset_position.load(Ordering::Relaxed);
261+
for _ in 0..self.capacity {
262+
current_position = (current_position + 1) % self.capacity;
263+
264+
if self.clear_bit(current_position) {
265+
self.reset_position
266+
.store(current_position, Ordering::Relaxed);
267+
return Some(current_position);
268+
}
269+
}
270+
271+
None
219272
}
220273

221274
/// Reset every set bit in the BitSet and call the provided callback for every bit that
222-
/// was set.
223-
pub fn reset<F: FnMut(usize)>(&self, mut callback: F) {
275+
/// was set. This is the most efficient way to acquire all bits that were set.
276+
pub fn reset_all<F: FnMut(usize)>(&self, mut callback: F) {
224277
self.verify_init("set");
225278
for i in 0..self.array_capacity {
226279
let value = unsafe { (*self.data_ptr.as_ptr().add(i)).swap(0, Ordering::Relaxed) };
@@ -282,7 +335,13 @@ impl<const CAPACITY: usize> FixedSizeBitSet<CAPACITY> {
282335

283336
/// Reset every set bit in the BitSet and call the provided callback for every bit that
284337
/// was set.
285-
pub fn reset<F: FnMut(usize)>(&self, callback: F) {
286-
self.bitset.reset(callback)
338+
pub fn reset_next(&self) -> Option<usize> {
339+
self.bitset.reset_next()
340+
}
341+
342+
/// Reset every set bit in the BitSet and call the provided callback for every bit that
343+
/// was set.
344+
pub fn reset_all<F: FnMut(usize)>(&self, callback: F) {
345+
self.bitset.reset_all(callback)
287346
}
288347
}

iceoryx2-bb/lock-free/tests/bitset_tests.rs

+41-8
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ fn bit_set_create_fill_and_reset_works() {
3737

3838
let mut id_set = HashSet::new();
3939
let mut counter = 0;
40-
sut.reset(|id| {
40+
sut.reset_all(|id| {
4141
assert_that!(id, lt CAPACITY);
4242
assert_that!(id_set.insert(id), eq true);
4343
counter += 1;
@@ -46,7 +46,7 @@ fn bit_set_create_fill_and_reset_works() {
4646
assert_that!(counter, eq CAPACITY);
4747

4848
let mut counter = 0;
49-
sut.reset(|_| {
49+
sut.reset_all(|_| {
5050
counter += 1;
5151
});
5252

@@ -67,7 +67,7 @@ fn fixed_size_bit_set_create_fill_and_reset_works() {
6767

6868
let mut id_set = HashSet::new();
6969
let mut counter = 0;
70-
sut.reset(|id| {
70+
sut.reset_all(|id| {
7171
assert_that!(id % 2 == 0, eq true);
7272
assert_that!(id, lt CAPACITY);
7373
assert_that!(id_set.insert(id), eq true);
@@ -77,7 +77,7 @@ fn fixed_size_bit_set_create_fill_and_reset_works() {
7777
assert_that!(counter, eq CAPACITY / 2);
7878

7979
let mut counter = 0;
80-
sut.reset(|_| {
80+
sut.reset_all(|_| {
8181
counter += 1;
8282
});
8383

@@ -92,12 +92,12 @@ fn bit_set_set_single_bit_works() {
9292
assert_that!(sut.set(55), eq true);
9393
assert_that!(sut.set(55), eq false);
9494

95-
sut.reset(|id| {
95+
sut.reset_all(|id| {
9696
assert_that!(id, eq 55);
9797
});
9898

9999
let mut counter = 0;
100-
sut.reset(|_| {
100+
sut.reset_all(|_| {
101101
counter += 1;
102102
});
103103

@@ -113,6 +113,39 @@ fn bit_set_set_bit_outside_of_bitset_leads_to_panic() {
113113
sut.set(CAPACITY);
114114
}
115115

116+
#[test]
117+
fn bit_set_set_and_reset_next_works() {
118+
const CAPACITY: usize = 1551;
119+
let sut = BitSet::new(CAPACITY);
120+
121+
assert_that!(sut.reset_next(), eq None);
122+
for i in 0..CAPACITY {
123+
assert_that!(sut.set(i), eq true);
124+
assert_that!(sut.reset_next(), eq Some(i));
125+
}
126+
assert_that!(sut.reset_next(), eq None);
127+
}
128+
129+
#[test]
130+
fn bit_set_reset_next_is_fair() {
131+
const CAPACITY: usize = 1551;
132+
let sut = BitSet::new(CAPACITY);
133+
134+
assert_that!(sut.set(0), eq true);
135+
assert_that!(sut.reset_next(), eq Some(0));
136+
137+
for i in 1..CAPACITY {
138+
assert_that!(sut.set(i - 1), eq true);
139+
assert_that!(sut.set(i), eq true);
140+
assert_that!(sut.reset_next(), eq Some(i));
141+
}
142+
143+
for i in 0..CAPACITY - 1 {
144+
assert_that!(sut.reset_next(), eq Some(i));
145+
}
146+
assert_that!(sut.reset_next(), eq None);
147+
}
148+
116149
#[test]
117150
fn bit_set_concurrent_set_and_reset_works() {
118151
let _watchdog = Watchdog::new(Duration::from_secs(10));
@@ -154,12 +187,12 @@ fn bit_set_concurrent_set_and_reset_works() {
154187

155188
barrier.wait();
156189
while keep_running.load(Ordering::Relaxed) {
157-
sut.reset(|id| {
190+
sut.reset_all(|id| {
158191
id_counter[id] += 1;
159192
});
160193
}
161194

162-
sut.reset(|id| {
195+
sut.reset_all(|id| {
163196
id_counter[id] += 1;
164197
});
165198

iceoryx2-cal/src/event/id_tracker.rs

Whitespace-only changes.

0 commit comments

Comments
 (0)