1use fuchsia_rcu::{RcuDroppable, RcuDroppableArc, RcuOptionBox};
42use smallvec::SmallVec;
43use starnix_rcu::RcuReadScope;
44use starnix_sync::{LockDepGuard, LockDepMutex, LockLevel};
45use std::sync::Arc;
46use std::sync::atomic::{AtomicU32, AtomicU64, Ordering};
47
48const BITS_PER_LEVEL: u32 = 6;
52const NODE_CAPACITY: usize = 1 << BITS_PER_LEVEL;
54const LEVEL_MASK: u32 = (1 << BITS_PER_LEVEL) - 1;
56const MAX_DEPTH: u32 = (32 + BITS_PER_LEVEL - 1) / BITS_PER_LEVEL;
58
59#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
61pub enum IdrAllocMode {
62 #[default]
64 Linear,
65 Cyclic {
68 min_after_wrap: Option<u32>,
70 },
71}
72
73pub struct Idr<T: RcuDroppable + Send + Sync + 'static, L: LockLevel> {
76 writer_lock: LockDepMutex<u32, L>,
80 root: RcuDroppableArc<IdrNode<T>>,
83 alloc_mode: IdrAllocMode,
85 max: AtomicU32,
87}
88
89impl<T: RcuDroppable + Send + Sync + 'static, L: LockLevel> Default for Idr<T, L> {
90 fn default() -> Self {
91 Self::new(IdrAllocMode::default())
92 }
93}
94
95impl<T: RcuDroppable + Send + Sync + 'static, L: LockLevel> Idr<T, L> {
96 pub fn new(alloc_mode: IdrAllocMode) -> Self {
98 Self {
99 writer_lock: LockDepMutex::new(0),
100 root: RcuDroppableArc::new(Arc::new(IdrNode::new(0))),
101 alloc_mode,
102 max: AtomicU32::new(u32::MAX),
103 }
104 }
105
106 pub fn new_cyclic(min_after_wrap: Option<u32>) -> Self {
108 Self::new(IdrAllocMode::Cyclic { min_after_wrap })
109 }
110
111 pub fn max(&self) -> u32 {
113 self.max.load(Ordering::Relaxed)
114 }
115
116 pub fn set_max(&self, max: u32) {
118 self.max.store(max, Ordering::Relaxed);
119 }
120
121 pub fn lock(&self) -> IdrGuard<'_, T, L> {
123 IdrGuard { idr: self, cursor: self.writer_lock.lock() }
124 }
125
126 pub fn lookup(&self, id: u32, scope: &RcuReadScope) -> Option<Arc<T>> {
128 let mut current_node = self.root.as_ref(scope);
129
130 let capacity = current_node.capacity();
131 if (id as u64) >= capacity {
132 return None;
133 }
134
135 loop {
136 let index = current_node.index_for_id(id);
137
138 let entry = current_node.children[index].as_ref(scope);
139 match entry {
140 Some(IdrEntry::Leaf(arc)) => return Some(arc.clone()),
141 Some(IdrEntry::Node(next)) => {
142 current_node = &**next;
143 }
144 None => return None,
145 }
146 }
147 }
148
149 pub fn iter<'a>(&'a self, scope: &'a RcuReadScope) -> IdrIterator<'a, T> {
151 let mut stack = SmallVec::new();
152 let root = self.root.as_ref(scope);
153 stack.push((root, 0, 0));
154 IdrIterator { scope, stack }
155 }
156
157 fn find_free_slot<'a>(
160 &self,
161 start_id: u32,
162 max_id: u32,
163 path: &mut SmallVec<[(&'a IdrNode<T>, usize); MAX_DEPTH as usize]>,
164 scope: &'a RcuReadScope,
165 ) -> Option<u32> {
166 if start_id > max_id {
167 return None;
168 }
169
170 struct StackEntry<'a, T: RcuDroppable + Send + Sync + 'static> {
173 node: &'a IdrNode<T>,
174 free_bits: u64,
176 min_constrained: bool,
178 max_constrained: bool,
180 chosen_index: usize,
182 }
183 let root = self.root.as_ref(scope);
184
185 let mut stack = SmallVec::<[StackEntry<'a, T>; MAX_DEPTH as usize]>::new();
186
187 let mut initial_free_bits = root.free_bitmap.load(Ordering::Relaxed);
189 let min_constrained = start_id > 0;
190 if min_constrained {
191 let cursor_index = root.index_for_id(start_id);
192 initial_free_bits &= !((1u64 << cursor_index) - 1);
193 }
194
195 let max_constrained = (max_id as u64) < root.capacity() - 1;
197 if max_constrained {
198 let max_index = root.index_for_id(max_id);
199 let max_mask = if max_index >= 63 { !0 } else { (1u64 << (max_index + 1)) - 1 };
200 initial_free_bits &= max_mask;
201 }
202
203 if initial_free_bits == 0 {
205 return None;
206 }
207
208 stack.push(StackEntry {
209 node: root,
210 free_bits: initial_free_bits,
211 min_constrained,
212 max_constrained,
213 chosen_index: 0,
214 });
215
216 while let Some(top) = stack.last_mut() {
217 if top.free_bits == 0 {
219 stack.pop();
220 continue;
221 }
222
223 let index = top.free_bits.trailing_zeros() as usize;
224 top.free_bits &= !(1u64 << index);
225 top.chosen_index = index;
226
227 let node = top.node;
228
229 if node.layer == 0 {
230 let id = stack
231 .iter()
232 .fold(0u32, |acc, entry| acc | entry.node.id_for_index(entry.chosen_index));
233 path.extend(stack.into_iter().map(|entry| (entry.node, entry.chosen_index)));
234 return Some(id);
235 }
236
237 let is_min_constrained = top.min_constrained && (index == node.index_for_id(start_id));
239 let is_max_constrained = top.max_constrained && (index == node.index_for_id(max_id));
240
241 let child = node.get_or_create_child(index, scope);
242 let mut child_free_bits = child.free_bitmap.load(Ordering::Relaxed);
243 if is_min_constrained {
244 let child_cursor = child.index_for_id(start_id);
245 child_free_bits &= !((1u64 << child_cursor) - 1);
246 }
247 if is_max_constrained {
248 let child_max = child.index_for_id(max_id);
249 let max_mask = if child_max >= 63 { !0 } else { (1u64 << (child_max + 1)) - 1 };
250 child_free_bits &= max_mask;
251 }
252
253 if child_free_bits == 0 {
255 continue;
256 }
257
258 stack.push(StackEntry {
259 node: child,
260 free_bits: child_free_bits,
261 min_constrained: is_min_constrained,
262 max_constrained: is_max_constrained,
263 chosen_index: 0,
264 });
265 }
266
267 None
268 }
269
270 fn propagate_fullness(&self, path: &[(&IdrNode<T>, usize)]) {
273 for i in (0..path.len() - 1).rev() {
274 let (parent, parent_index) = &path[i];
275 if !parent.mark_allocated(*parent_index) {
276 break;
278 }
279 }
280 }
281
282 fn propagate_availability(&self, path: &[(&IdrNode<T>, usize)]) {
285 for i in (0..path.len() - 1).rev() {
286 let (parent, parent_index) = &path[i];
287
288 if !parent.mark_freed(*parent_index) {
289 break;
291 }
292 }
293 }
294
295 fn grow_tree_by_one_layer(&self, root_arc: &Arc<IdrNode<T>>) -> Option<Arc<IdrNode<T>>> {
298 let next_layer = root_arc.layer + 1;
299 if next_layer >= MAX_DEPTH {
300 return None;
301 }
302
303 let new_root = Arc::new(IdrNode::new(next_layer));
304 if root_arc.free_bitmap.load(Ordering::Relaxed) == 0 {
305 new_root.free_bitmap.fetch_and(!1, Ordering::Relaxed);
306 }
307 new_root.mark_present(0);
308 new_root.children[0].update(Some(IdrEntry::Node(root_arc.clone())));
309 self.root.update(new_root.clone());
310 Some(new_root)
311 }
312}
313
314pub struct IdrGuard<'a, T: RcuDroppable + Send + Sync + 'static, L: LockLevel> {
319 idr: &'a Idr<T, L>,
320 cursor: LockDepGuard<'a, u32>,
321}
322
323impl<'a, T: RcuDroppable + Send + Sync + 'static, L: LockLevel> std::ops::Deref
324 for IdrGuard<'a, T, L>
325{
326 type Target = Idr<T, L>;
327
328 fn deref(&self) -> &Self::Target {
329 self.idr
330 }
331}
332
333impl<'a, T: RcuDroppable + Send + Sync + 'static, L: LockLevel> IdrGuard<'a, T, L> {
334 pub fn alloc<F>(&mut self, factory: F) -> Option<(u32, Arc<T>)>
340 where
341 F: FnOnce(u32) -> Arc<T>,
342 {
343 let max_id = self.idr.max.load(Ordering::Relaxed);
344
345 let (is_cyclic, wrap_min) = match self.idr.alloc_mode {
346 IdrAllocMode::Linear => (false, 0),
347 IdrAllocMode::Cyclic { min_after_wrap } => (true, min_after_wrap.unwrap_or(0)),
348 };
349
350 let (start_id, wrapped) = if is_cyclic {
351 if *self.cursor > max_id { (wrap_min, true) } else { (*self.cursor, false) }
352 } else {
353 (0, false)
354 };
355
356 if start_id > max_id {
357 return None;
358 }
359
360 let mut root_arc = self.idr.root.to_arc();
361
362 while (start_id as u64) >= root_arc.capacity()
368 || (root_arc.free_bitmap.load(Ordering::Relaxed) == 0
369 && root_arc.capacity() <= (max_id as u64))
370 {
371 if let Some(new_root) = self.idr.grow_tree_by_one_layer(&root_arc) {
372 root_arc = new_root;
373 } else {
374 return None;
376 }
377 }
378
379 let scope = RcuReadScope::new();
380 let mut path = SmallVec::<[(&IdrNode<T>, usize); MAX_DEPTH as usize]>::new();
381 let id_opt = self.idr.find_free_slot(start_id, max_id, &mut path, &scope).or_else(|| {
383 if is_cyclic && !wrapped && start_id > wrap_min && wrap_min <= max_id {
386 path.clear();
387 self.idr.find_free_slot(wrap_min, max_id, &mut path, &scope)
388 } else {
389 None
390 }
391 });
392
393 let id = id_opt?;
394 let (leaf_node, leaf_index) = path.last().expect("path should not be empty");
395 let leaf_index = *leaf_index;
396 let item = factory(id);
397
398 leaf_node.children[leaf_index].update(Some(IdrEntry::Leaf(item.clone())));
400 leaf_node.mark_present(leaf_index);
401
402 if leaf_node.mark_allocated(leaf_index) {
405 self.idr.propagate_fullness(&path);
406 }
407
408 if is_cyclic {
411 let next_cursor = id.wrapping_add(1);
412 *self.cursor = if next_cursor > max_id || (next_cursor == 0 && wrap_min > 0) {
413 wrap_min
414 } else {
415 next_cursor
416 };
417 }
418 Some((id, item))
419 }
420
421 pub fn reserve_id(&mut self, id: u32) {
424 let mut root_arc = self.idr.root.to_arc();
425
426 loop {
427 let capacity = root_arc.capacity();
428 if (id as u64) < capacity {
429 break;
430 }
431 if let Some(new_root) = self.idr.grow_tree_by_one_layer(&root_arc) {
432 root_arc = new_root;
433 } else {
434 return; }
436 }
437
438 let scope = RcuReadScope::new();
439 let mut current_node = root_arc.as_ref();
440 let mut path = SmallVec::<[(&IdrNode<T>, usize); MAX_DEPTH as usize]>::new();
441
442 loop {
443 let index = current_node.index_for_id(id);
444
445 path.push((current_node, index));
446
447 if current_node.layer == 0 {
449 if current_node.mark_allocated(index) {
451 self.idr.propagate_fullness(&path);
452 }
453 return;
454 }
455
456 current_node = current_node.get_or_create_child(index, &scope);
458 }
459 }
460
461 pub fn remove(&mut self, id: u32) {
463 let scope = RcuReadScope::new();
464
465 let mut current_node = self.idr.root.as_ref(&scope);
466
467 if (id as u64) >= current_node.capacity() {
468 return;
469 }
470
471 let mut path = SmallVec::<[(&IdrNode<T>, usize); MAX_DEPTH as usize]>::new();
472
473 loop {
474 let index = current_node.index_for_id(id);
475
476 path.push((current_node, index));
477
478 let Some(child) = current_node.children[index].as_ref(&scope) else {
479 return;
481 };
482
483 if current_node.layer == 0 {
484 current_node.children[index].update(None);
485 current_node.mark_absent(index);
486 if current_node.mark_freed(index) {
487 self.idr.propagate_availability(&path);
488 }
489 return;
490 } else {
491 current_node = match child {
492 IdrEntry::Node(n) => &**n,
493 _ => unreachable!("Tree corruption: expected a Node entry here"),
494 };
495 }
496 }
497 }
498
499 #[cfg(test)]
501 fn cursor(&self) -> u32 {
502 *self.cursor
503 }
504
505 #[cfg(test)]
507 fn set_cursor(&mut self, cursor: u32) {
508 *self.cursor = cursor;
509 }
510}
511
512pub struct IdrIterator<'a, T: RcuDroppable + Send + Sync + 'static> {
515 scope: &'a RcuReadScope,
517 stack: SmallVec<[(&'a IdrNode<T>, usize, u32); MAX_DEPTH as usize]>,
520}
521
522impl<'a, T: RcuDroppable + Send + Sync + 'static> Iterator for IdrIterator<'a, T> {
523 type Item = (u32, &'a Arc<T>);
524
525 fn next(&mut self) -> Option<Self::Item> {
526 while let Some((node, index, id_base)) = self.stack.pop() {
527 let presence = node.presence_bitmap.load(Ordering::Relaxed);
528
529 let mask = if index >= NODE_CAPACITY { 0 } else { !((1u64 << index) - 1) };
530 let remaining = presence & mask;
531
532 if remaining == 0 {
533 continue;
534 }
535
536 let next_bit = remaining.trailing_zeros() as usize;
537
538 self.stack.push((node, next_bit + 1, id_base));
539
540 let entry_opt = node.children[next_bit].as_ref(self.scope);
541 if let Some(entry) = entry_opt {
542 let child_id = id_base | node.id_for_index(next_bit);
543
544 match entry {
545 IdrEntry::Node(child_arc) => {
546 self.stack.push((child_arc.as_ref(), 0, child_id));
547 }
548 IdrEntry::Leaf(arc) => {
549 return Some((child_id, arc));
550 }
551 }
552 }
553 }
554 None
555 }
556}
557
558#[derive(Debug)]
560enum IdrEntry<T: RcuDroppable + Send + Sync + 'static> {
561 Node(Arc<IdrNode<T>>),
563 Leaf(Arc<T>),
565}
566
567unsafe impl<T: RcuDroppable + Send + Sync + 'static> RcuDroppable for IdrEntry<T> {}
571
572#[derive(Debug, RcuDroppable)]
573struct IdrNode<T: RcuDroppable + Send + Sync + 'static> {
574 layer: u32,
577
578 free_bitmap: AtomicU64,
582
583 presence_bitmap: AtomicU64,
587
588 children: [RcuOptionBox<IdrEntry<T>>; NODE_CAPACITY],
591}
592
593impl<T: RcuDroppable + Send + Sync + 'static> Default for IdrNode<T> {
594 fn default() -> Self {
595 Self::new(0)
596 }
597}
598
599impl<T: RcuDroppable + Send + Sync + 'static> IdrNode<T> {
600 fn new(layer: u32) -> Self {
601 let children = std::array::from_fn(|_| RcuOptionBox::new(None));
602 Self {
603 layer,
604 free_bitmap: AtomicU64::new(!0), presence_bitmap: AtomicU64::new(0),
606 children,
607 }
608 }
609
610 #[inline]
613 fn capacity(&self) -> u64 {
614 1u64 << (BITS_PER_LEVEL * (self.layer + 1))
615 }
616
617 #[inline]
619 fn index_for_id(&self, id: u32) -> usize {
620 ((id >> (self.layer * BITS_PER_LEVEL)) & LEVEL_MASK) as usize
621 }
622
623 #[inline]
626 fn id_for_index(&self, index: usize) -> u32 {
627 (index as u32) << (self.layer * BITS_PER_LEVEL)
628 }
629
630 #[inline]
633 fn mark_allocated(&self, index: usize) -> bool {
634 let old_free = self.free_bitmap.fetch_and(!(1 << index), Ordering::Relaxed);
635 old_free == (1 << index)
636 }
637
638 #[inline]
642 fn mark_freed(&self, index: usize) -> bool {
643 let old_free = self.free_bitmap.fetch_or(1 << index, Ordering::Relaxed);
644 old_free == 0
645 }
646
647 #[inline]
649 fn mark_present(&self, index: usize) {
650 self.presence_bitmap.fetch_or(1 << index, Ordering::Relaxed);
651 }
652
653 #[inline]
655 fn mark_absent(&self, index: usize) {
656 self.presence_bitmap.fetch_and(!(1 << index), Ordering::Relaxed);
657 }
658
659 fn get_or_create_child<'a>(&'a self, index: usize, scope: &'a RcuReadScope) -> &'a IdrNode<T> {
663 debug_assert!(self.layer > 0);
664 if let Some(IdrEntry::Node(n)) = self.children[index].as_ref(scope) {
665 return &**n;
666 }
667
668 let new_node = Arc::new(IdrNode::new(self.layer - 1));
669 self.children[index].update(Some(IdrEntry::Node(new_node)));
670 self.mark_present(index);
671 match self.children[index].as_ref(scope).unwrap() {
672 IdrEntry::Node(n) => &**n,
673 _ => unreachable!("Tree corruption: expected a Node entry here"),
674 }
675 }
676}
677
678#[cfg(test)]
679mod tests {
680 use super::*;
681 use starnix_sync::lock_ordering;
682 use std::sync::Arc;
683 use std::sync::atomic::{AtomicBool, Ordering};
684
685 lock_ordering! {
686 Terminal(TestIdrLock),
687 }
688
689 type Idr<T> = super::Idr<T, TestIdrLock>;
690
691 #[derive(RcuDroppable)]
692 struct MockItem {
693 value: u32,
694 }
695
696 #[fuchsia::test]
697 fn test_basic_alloc_lookup() {
698 let idr = Idr::default();
699 assert_eq!(idr.alloc_mode, IdrAllocMode::Linear);
700
701 let (id1, _item1) = idr.lock().alloc(|id| Arc::new(MockItem { value: id * 10 })).unwrap();
702 assert_eq!(id1, 0);
703
704 let (id2, _item2) = idr.lock().alloc(|id| Arc::new(MockItem { value: id * 10 })).unwrap();
705 assert_eq!(id2, 1);
706
707 let scope = RcuReadScope::new();
708 let lookup1 = idr.lookup(0, &scope).unwrap();
709 assert_eq!(lookup1.value, 0);
710
711 let lookup2 = idr.lookup(1, &scope).unwrap();
712 assert_eq!(lookup2.value, 10);
713
714 idr.lock().remove(0);
715 assert!(idr.lookup(0, &scope).is_none());
716
717 let lookup_still_there = idr.lookup(1, &scope).unwrap();
719 assert_eq!(lookup_still_there.value, 10);
720 }
721
722 #[fuchsia::test]
723 fn test_tree_growth() {
724 let idr = Idr::default();
725 let mut _items = Vec::new();
726
727 for i in 0..150 {
730 let (id, item) = idr.lock().alloc(|id| Arc::new(MockItem { value: id })).unwrap();
731 _items.push(item);
732 assert_eq!(id, i);
733 }
734
735 let scope = RcuReadScope::new();
736 for i in 0..150 {
737 let item = idr.lookup(i, &scope).unwrap();
738 assert_eq!(item.value, i);
739 }
740 }
741
742 #[fuchsia::test]
743 fn test_alloc_cyclic() {
744 let idr = Idr::new_cyclic(None);
745 let mut _items = Vec::new();
746
747 for i in 0..30 {
748 let (id, item) = idr.lock().alloc(|id| Arc::new(MockItem { value: id })).unwrap();
749 _items.push(item);
750 assert_eq!(id, i);
751 }
752
753 idr.lock().set_cursor(100);
755
756 let (id, item1) = idr.lock().alloc(|id| Arc::new(MockItem { value: id })).unwrap();
758 _items.push(item1);
759 assert_eq!(id, 100);
760
761 let (id, item2) = idr.lock().alloc(|id| Arc::new(MockItem { value: id })).unwrap();
762 _items.push(item2);
763 assert_eq!(id, 101);
764
765 let scope = RcuReadScope::new();
766 assert!(idr.lookup(30, &scope).is_none());
767 assert_eq!(idr.lookup(100, &scope).unwrap().value, 100);
768 }
769
770 #[fuchsia::test]
771 fn test_alloc_cyclic_start_exceeds_capacity() {
772 let idr = Idr::new_cyclic(None);
773 let mut _items = Vec::new();
774
775 idr.lock().set_cursor(256);
777
778 let (id, item) = idr.lock().alloc(|id| Arc::new(MockItem { value: id })).unwrap();
779 _items.push(item);
780
781 assert_eq!(id, 256);
783 }
784
785 #[fuchsia::test]
786 fn test_reserve_id() {
787 let idr = Idr::new_cyclic(None);
788 let mut _items = Vec::new();
789
790 idr.lock().reserve_id(10);
792
793 let (id1, item1) = idr.lock().alloc(|id| Arc::new(MockItem { value: id })).unwrap();
794 _items.push(item1);
795 assert_eq!(id1, 0);
796
797 idr.lock().reserve_id(200);
799
800 let mut allocated_10 = false;
802 for _ in 1..15 {
803 let (id, item) = idr.lock().alloc(|id| Arc::new(MockItem { value: id })).unwrap();
804 _items.push(item);
805 if id == 10 {
806 allocated_10 = true;
807 }
808 }
809 assert!(!allocated_10, "ID 10 was allocated despite being reserved");
810
811 idr.lock().set_cursor(199);
813
814 let mut allocated_200 = false;
815 for _ in 0..5 {
816 let (id, item) = idr.lock().alloc(|id| Arc::new(MockItem { value: id })).unwrap();
817 _items.push(item);
818 if id == 200 {
819 allocated_200 = true;
820 }
821 }
822 assert!(!allocated_200, "ID 200 was allocated despite being reserved");
823
824 let scope = RcuReadScope::new();
825 assert!(idr.lookup(10, &scope).is_none());
827 assert!(idr.lookup(200, &scope).is_none());
828
829 idr.lock().remove(10);
831 idr.lock().remove(200);
832 assert!(idr.lookup(10, &scope).is_none());
833 }
834
835 #[fuchsia::test]
836 fn test_iter_and_remove() {
837 let idr = Idr::default();
838 let mut _items = Vec::new();
839
840 _items.push(idr.lock().alloc(|_| Arc::new(MockItem { value: 10 })).unwrap().1);
842 _items.push(idr.lock().alloc(|_| Arc::new(MockItem { value: 20 })).unwrap().1);
844 _items.push(idr.lock().alloc(|_| Arc::new(MockItem { value: 30 })).unwrap().1);
846
847 idr.lock().remove(1);
849
850 let scope = RcuReadScope::new();
851 let mut iter = idr.iter(&scope);
852
853 let next_a = iter.next();
854 let (id_a, item_a) = next_a.unwrap();
855 assert_eq!(id_a, 0);
856 assert_eq!(item_a.value, 10);
857
858 let (id_b, item_b) = iter.next().unwrap();
859 assert_eq!(id_b, 2);
860 assert_eq!(item_b.value, 30);
861
862 assert!(iter.next().is_none());
863 }
864
865 #[fuchsia::test]
866 fn test_iter_minimal() {
867 let idr = Idr::default();
868 let mut _items = Vec::new();
869 _items.push(idr.lock().alloc(|value| Arc::new(MockItem { value })).unwrap().1);
870 let scope = RcuReadScope::new();
871 let mut iter = idr.iter(&scope);
872 let next_a = iter.next();
873 assert!(next_a.is_some(), "iter.next() returned None!");
874 }
875
876 #[fuchsia::test]
877 fn test_alloc_cyclic_with_gaps() {
878 let idr = Idr::new_cyclic(None);
879 let mut _items = Vec::new();
880
881 for i in 0..100 {
883 let (id, item) = idr.lock().alloc(|id| Arc::new(MockItem { value: id })).unwrap();
884 assert_eq!(id, i);
885 _items.push(item);
886 }
887
888 for id in 40..50 {
890 idr.lock().remove(id);
891 }
892
893 idr.lock().set_cursor(50);
895
896 let (id_100, item_100) = idr.lock().alloc(|id| Arc::new(MockItem { value: id })).unwrap();
899 assert_eq!(id_100, 100);
900 _items.push(item_100);
901
902 for expected in 101..130 {
904 let (id, item) = idr.lock().alloc(|id| Arc::new(MockItem { value: id })).unwrap();
905 assert_eq!(id, expected);
906 _items.push(item);
907 }
908 }
909
910 #[fuchsia::test]
911 fn test_concurrent_readers_and_writers() {
912 let idr = Arc::new(Idr::new_cyclic(None));
913 let running = Arc::new(AtomicBool::new(true));
914
915 for _i in 0..50 {
917 idr.lock().alloc(|id| Arc::new(MockItem { value: id })).unwrap();
918 }
919
920 let mut reader_handles = Vec::new();
921 for _ in 0..4 {
922 let idr_clone = Arc::clone(&idr);
923 let running_clone = Arc::clone(&running);
924 reader_handles.push(std::thread::spawn(move || {
925 while running_clone.load(Ordering::Relaxed) {
926 let scope = RcuReadScope::new();
927 for id in 0..100 {
929 if let Some(item) = idr_clone.lookup(id, &scope) {
930 assert_eq!(item.value, id);
931 }
932 }
933
934 let iter = idr_clone.iter(&scope);
936 for (id, item) in iter {
937 assert_eq!(item.value, id);
938 }
939 }
940 }));
941 }
942
943 let running_clone = Arc::clone(&running);
944 let rcu_advancer = std::thread::spawn(move || {
945 while running_clone.load(Ordering::Relaxed) {
946 fuchsia_rcu::rcu_run_callbacks();
947 std::thread::sleep(std::time::Duration::from_millis(1));
948 }
949 });
950
951 let idr_clone = Arc::clone(&idr);
953 let writer_handle = std::thread::spawn(move || {
954 for _ in 0..200 {
955 let (id, _) =
956 idr_clone.lock().alloc(|id| Arc::new(MockItem { value: id })).unwrap();
957 if id > 50 && id % 3 == 0 {
958 idr_clone.lock().remove(id);
959 }
960 }
961 });
962
963 writer_handle.join().unwrap();
964 running.store(false, Ordering::Relaxed);
965 rcu_advancer.join().unwrap();
966
967 for handle in reader_handles {
968 handle.join().unwrap();
969 }
970 }
971
972 #[fuchsia::test]
973 fn test_u32_max_wrap_around() {
974 let idr = Idr::<MockItem>::new_cyclic(None);
975 idr.lock().set_cursor(u32::MAX);
976
977 let (id1, _item1) = idr.lock().alloc(|id| Arc::new(MockItem { value: id })).unwrap();
979 assert_eq!(id1, u32::MAX);
980
981 let (id2, _item2) = idr.lock().alloc(|id| Arc::new(MockItem { value: id })).unwrap();
983 assert_eq!(id2, 0);
984
985 let scope = RcuReadScope::new();
987 assert_eq!(idr.lookup(u32::MAX, &scope).unwrap().value, u32::MAX);
988 assert_eq!(idr.lookup(0, &scope).unwrap().value, 0);
989 }
990
991 #[fuchsia::test]
992 fn test_overflow_bug_at_u32_max() {
993 let idr = Idr::<MockItem>::new_cyclic(None);
994
995 idr.lock().reserve_id(0);
998
999 idr.lock().reserve_id(u32::MAX);
1007
1008 idr.lock().set_cursor(u32::MAX);
1009
1010 let (id, _) = idr.lock().alloc(|id| Arc::new(MockItem { value: id })).unwrap();
1011 assert_eq!(id, 1);
1012
1013 let scope = RcuReadScope::new();
1014 assert!(idr.lookup(1, &scope).is_some());
1015 }
1016
1017 #[fuchsia::test]
1018 fn test_lock_held_across_operations() {
1019 let idr = Idr::<MockItem>::default();
1020
1021 let mut guard = idr.lock();
1023 assert_eq!(guard.cursor(), 0);
1024
1025 guard.reserve_id(0);
1026 let (id1, item1) = guard.alloc(|value| Arc::new(MockItem { value })).unwrap();
1027 assert_eq!(id1, 1);
1028 assert_eq!(item1.value, 1);
1029
1030 let (id2, item2) = guard.alloc(|value| Arc::new(MockItem { value })).unwrap();
1031 assert_eq!(id2, 2);
1032 assert_eq!(item2.value, 2);
1033
1034 guard.remove(1);
1035
1036 let (id3, item3) = guard.alloc(|value| Arc::new(MockItem { value })).unwrap();
1038 assert_eq!(id3, 1);
1039 assert_eq!(item3.value, 1);
1040
1041 let scope = RcuReadScope::new();
1043 assert_eq!(guard.lookup(1, &scope).unwrap().value, 1);
1044 assert_eq!(guard.lookup(2, &scope).unwrap().value, 2);
1045
1046 let (id4, _) = guard.alloc(|value| Arc::new(MockItem { value })).unwrap();
1048 assert_eq!(id4, 3);
1049
1050 guard.set_cursor(50);
1051 assert_eq!(guard.cursor(), 50);
1052 }
1053
1054 #[fuchsia::test]
1055 fn test_alloc_cyclic_min_after_wrap() {
1056 let idr = Idr::<MockItem>::new_cyclic(Some(2));
1057 assert_eq!(idr.alloc_mode, IdrAllocMode::Cyclic { min_after_wrap: Some(2) });
1058 let mut guard = idr.lock();
1059
1060 let (id0, _) = guard.alloc(|value| Arc::new(MockItem { value })).unwrap();
1062 assert_eq!(id0, 0);
1063 let (id1, _) = guard.alloc(|value| Arc::new(MockItem { value })).unwrap();
1064 assert_eq!(id1, 1);
1065 let (id2, _) = guard.alloc(|value| Arc::new(MockItem { value })).unwrap();
1066 assert_eq!(id2, 2);
1067 let (id3, _) = guard.alloc(|value| Arc::new(MockItem { value })).unwrap();
1068 assert_eq!(id3, 3);
1069 let (id4, _) = guard.alloc(|value| Arc::new(MockItem { value })).unwrap();
1070 assert_eq!(id4, 4);
1071
1072 guard.remove(0);
1074 guard.remove(1);
1075
1076 for i in 10..64 {
1078 guard.reserve_id(i);
1079 }
1080
1081 guard.set_cursor(10);
1083
1084 let (id5, _) = guard.alloc(|value| Arc::new(MockItem { value })).unwrap();
1088 assert_eq!(id5, 5);
1089
1090 for expected in 6..10 {
1092 let (id, _) = guard.alloc(|value| Arc::new(MockItem { value })).unwrap();
1093 assert_eq!(id, expected);
1094 }
1095
1096 assert!(guard.alloc(|value| Arc::new(MockItem { value })).is_none());
1101 }
1102
1103 #[fuchsia::test]
1104 fn test_alloc_cyclic_wrap_without_min_after_wrap() {
1105 let idr = Idr::<MockItem>::new_cyclic(None);
1107 let mut guard = idr.lock();
1108 let (z0, _) = guard.alloc(|value| Arc::new(MockItem { value })).unwrap();
1109 assert_eq!(z0, 0);
1110 let (z1, _) = guard.alloc(|value| Arc::new(MockItem { value })).unwrap();
1111 assert_eq!(z1, 1);
1112 guard.remove(0);
1113 guard.remove(1);
1114 guard.set_cursor(10);
1115 for i in 10..64 {
1116 guard.reserve_id(i);
1117 }
1118 let (id0_after, _) = guard.alloc(|value| Arc::new(MockItem { value })).unwrap();
1119 assert_eq!(id0_after, 0);
1120
1121 let (id1_after, _) = guard.alloc(|value| Arc::new(MockItem { value })).unwrap();
1122 assert_eq!(id1_after, 1);
1123 }
1124
1125 #[fuchsia::test]
1126 fn test_alloc_cyclic_min_after_wrap_at_u32_max() {
1127 let idr = Idr::<MockItem>::new_cyclic(Some(2));
1128 let mut guard = idr.lock();
1129
1130 guard.set_cursor(u32::MAX);
1132
1133 let (id_max, _) = guard.alloc(|value| Arc::new(MockItem { value })).unwrap();
1135 assert_eq!(id_max, u32::MAX);
1136
1137 assert_eq!(guard.cursor(), 2);
1139
1140 let (id2, _) = guard.alloc(|value| Arc::new(MockItem { value })).unwrap();
1142 assert_eq!(id2, 2);
1143 assert_eq!(guard.cursor(), 3);
1144
1145 let scope = RcuReadScope::new();
1146 assert!(guard.lookup(0, &scope).is_none());
1147 assert!(guard.lookup(1, &scope).is_none());
1148 assert!(guard.lookup(2, &scope).is_some());
1149 assert!(guard.lookup(u32::MAX, &scope).is_some());
1150 }
1151
1152 #[fuchsia::test]
1153 fn test_linear_alloc_max() {
1154 let idr = Idr::<MockItem>::default();
1155 idr.set_max(3);
1156 assert_eq!(idr.max(), 3);
1157
1158 let mut guard = idr.lock();
1159 assert_eq!(guard.alloc(|value| Arc::new(MockItem { value })).unwrap().0, 0);
1160 assert_eq!(guard.alloc(|value| Arc::new(MockItem { value })).unwrap().0, 1);
1161 assert_eq!(guard.alloc(|value| Arc::new(MockItem { value })).unwrap().0, 2);
1162 assert_eq!(guard.alloc(|value| Arc::new(MockItem { value })).unwrap().0, 3);
1163
1164 assert!(guard.alloc(|value| Arc::new(MockItem { value })).is_none());
1166
1167 guard.remove(1);
1169 assert_eq!(guard.alloc(|value| Arc::new(MockItem { value })).unwrap().0, 1);
1170 assert!(guard.alloc(|value| Arc::new(MockItem { value })).is_none());
1171 }
1172
1173 #[fuchsia::test]
1174 fn test_update_max() {
1175 let idr = Idr::<MockItem>::default();
1176 idr.set_max(2);
1177 let mut guard = idr.lock();
1178
1179 assert_eq!(guard.alloc(|value| Arc::new(MockItem { value })).unwrap().0, 0);
1180 assert_eq!(guard.alloc(|value| Arc::new(MockItem { value })).unwrap().0, 1);
1181 assert_eq!(guard.alloc(|value| Arc::new(MockItem { value })).unwrap().0, 2);
1182 assert!(guard.alloc(|value| Arc::new(MockItem { value })).is_none());
1183
1184 guard.set_max(5);
1186 assert_eq!(guard.max(), 5);
1187
1188 assert_eq!(guard.alloc(|value| Arc::new(MockItem { value })).unwrap().0, 3);
1189 assert_eq!(guard.alloc(|value| Arc::new(MockItem { value })).unwrap().0, 4);
1190 assert_eq!(guard.alloc(|value| Arc::new(MockItem { value })).unwrap().0, 5);
1191 assert!(guard.alloc(|value| Arc::new(MockItem { value })).is_none());
1192
1193 guard.set_max(4);
1195 let scope = RcuReadScope::new();
1196 assert!(guard.lookup(5, &scope).is_some());
1197
1198 guard.remove(5);
1200 assert!(guard.alloc(|value| Arc::new(MockItem { value })).is_none());
1201
1202 guard.remove(2);
1204 assert_eq!(guard.alloc(|value| Arc::new(MockItem { value })).unwrap().0, 2);
1205 assert!(guard.alloc(|value| Arc::new(MockItem { value })).is_none());
1206 }
1207
1208 #[fuchsia::test]
1209 fn test_cyclic_alloc_max_wrapping() {
1210 let idr = Idr::<MockItem>::new_cyclic(Some(2));
1211 idr.set_max(5);
1212 let mut guard = idr.lock();
1213
1214 for expected in 0..=5 {
1216 assert_eq!(guard.alloc(|value| Arc::new(MockItem { value })).unwrap().0, expected);
1217 }
1218
1219 assert_eq!(guard.cursor(), 2);
1221
1222 assert!(guard.alloc(|value| Arc::new(MockItem { value })).is_none());
1224
1225 guard.remove(3);
1227 assert_eq!(guard.alloc(|value| Arc::new(MockItem { value })).unwrap().0, 3);
1228 assert_eq!(guard.cursor(), 4);
1229
1230 guard.remove(0);
1232 guard.remove(1);
1233 assert!(guard.alloc(|value| Arc::new(MockItem { value })).is_none());
1234 }
1235
1236 #[fuchsia::test]
1237 fn test_cyclic_cursor_above_new_max() {
1238 let idr = Idr::<MockItem>::new_cyclic(None);
1239 let mut guard = idr.lock();
1240
1241 guard.set_cursor(80);
1243 assert_eq!(guard.alloc(|value| Arc::new(MockItem { value })).unwrap().0, 80);
1244 assert_eq!(guard.cursor(), 81);
1245
1246 guard.set_max(50);
1248
1249 assert_eq!(guard.alloc(|value| Arc::new(MockItem { value })).unwrap().0, 0);
1251 assert_eq!(guard.cursor(), 1);
1252 }
1253
1254 #[fuchsia::test]
1255 fn test_max_across_tree_layers() {
1256 let idr = Idr::<MockItem>::default();
1258 idr.set_max(70);
1259 let mut guard = idr.lock();
1260
1261 for expected in 0..=70 {
1262 assert_eq!(guard.alloc(|value| Arc::new(MockItem { value })).unwrap().0, expected);
1263 }
1264
1265 assert!(guard.alloc(|value| Arc::new(MockItem { value })).is_none());
1267
1268 guard.set_max(75);
1270 for expected in 71..=75 {
1271 assert_eq!(guard.alloc(|value| Arc::new(MockItem { value })).unwrap().0, expected);
1272 }
1273 assert!(guard.alloc(|value| Arc::new(MockItem { value })).is_none());
1274 }
1275
1276 #[fuchsia::test]
1277 fn test_max_zero() {
1278 let idr = Idr::<MockItem>::default();
1279 idr.set_max(0);
1280 let mut guard = idr.lock();
1281
1282 assert_eq!(guard.alloc(|value| Arc::new(MockItem { value })).unwrap().0, 0);
1283 assert!(guard.alloc(|value| Arc::new(MockItem { value })).is_none());
1284 }
1285}