tokio/util/
sharded_list.rs1use std::ptr::NonNull;
2use std::sync::atomic::Ordering;
3
4use crate::loom::sync::{Mutex, MutexGuard};
5use crate::util::metric_atomics::{MetricAtomicU64, MetricAtomicUsize};
6
7use super::linked_list::{Link, LinkedList};
8
9pub(crate) struct ShardedList<L, T> {
16 lists: Box<[Mutex<LinkedList<L, T>>]>,
17 added: MetricAtomicU64,
18 count: MetricAtomicUsize,
19 shard_mask: usize,
20}
21
22pub(crate) unsafe trait ShardedListItem: Link {
29 unsafe fn get_shard_id(target: NonNull<Self::Target>) -> usize;
32}
33
34impl<L, T> ShardedList<L, T> {
35 pub(crate) fn new(sharded_size: usize) -> Self {
37 assert!(sharded_size.is_power_of_two());
38
39 let shard_mask = sharded_size - 1;
40 let mut lists = Vec::with_capacity(sharded_size);
41 for _ in 0..sharded_size {
42 lists.push(Mutex::new(LinkedList::<L, T>::new()))
43 }
44 Self {
45 lists: lists.into_boxed_slice(),
46 added: MetricAtomicU64::new(0),
47 count: MetricAtomicUsize::new(0),
48 shard_mask,
49 }
50 }
51}
52
53pub(crate) struct ShardGuard<'a, L, T> {
55 lock: MutexGuard<'a, LinkedList<L, T>>,
56 added: &'a MetricAtomicU64,
57 count: &'a MetricAtomicUsize,
58 id: usize,
59}
60
61impl<L: ShardedListItem> ShardedList<L, L::Target> {
62 pub(crate) fn pop_back(&self, shard_id: usize) -> Option<L::Handle> {
65 let mut lock = self.shard_inner(shard_id);
66 let node = lock.pop_back();
67 if node.is_some() {
68 self.count.decrement();
69 }
70 node
71 }
72
73 pub(crate) unsafe fn remove(&self, node: NonNull<L::Target>) -> Option<L::Handle> {
82 let id = L::get_shard_id(node);
83 let mut lock = self.shard_inner(id);
84 let node = unsafe { lock.remove(node) };
87 if node.is_some() {
88 self.count.decrement();
89 }
90 node
91 }
92
93 pub(crate) fn lock_shard(&self, val: &L::Handle) -> ShardGuard<'_, L, L::Target> {
95 let id = unsafe { L::get_shard_id(L::as_raw(val)) };
96 ShardGuard {
97 lock: self.shard_inner(id),
98 added: &self.added,
99 count: &self.count,
100 id,
101 }
102 }
103
104 pub(crate) fn len(&self) -> usize {
106 self.count.load(Ordering::Relaxed)
107 }
108
109 cfg_64bit_metrics! {
110 pub(crate) fn added(&self) -> u64 {
112 self.added.load(Ordering::Relaxed)
113 }
114 }
115
116 pub(crate) fn is_empty(&self) -> bool {
118 self.len() == 0
119 }
120
121 pub(crate) fn shard_size(&self) -> usize {
125 self.shard_mask + 1
126 }
127
128 #[inline]
129 fn shard_inner(&self, id: usize) -> MutexGuard<'_, LinkedList<L, <L as Link>::Target>> {
130 unsafe { self.lists.get_unchecked(id & self.shard_mask).lock() }
132 }
133}
134
135impl<'a, L: ShardedListItem> ShardGuard<'a, L, L::Target> {
136 pub(crate) fn push(mut self, val: L::Handle) {
138 let id = unsafe { L::get_shard_id(L::as_raw(&val)) };
139 assert_eq!(id, self.id);
140 self.lock.push_front(val);
141 self.added.add(1, Ordering::Relaxed);
142 self.count.increment();
143 }
144}
145
146cfg_taskdump! {
147 impl<L: ShardedListItem> ShardedList<L, L::Target> {
148 pub(crate) fn for_each<F>(&self, mut f: F)
149 where
150 F: FnMut(&L::Handle),
151 {
152 let mut guards = Vec::with_capacity(self.lists.len());
153 for list in self.lists.iter() {
154 guards.push(list.lock());
155 }
156 for g in &mut guards {
157 g.for_each(&mut f);
158 }
159 }
160 }
161}