1use alloc::boxed::Box;
2use core::{marker::PhantomData, ptr::null_mut};
3
4use crossbeam_utils::CachePadded;
5
6use crate::{
7 MPMCQueue,
8 Resize,
9 core::{
10 AsPackedValue,
11 queue::QueueCore,
12 slots::{Auto, SlotType},
13 },
14 growable::NewSized,
15 owned::buffer::BoxedBuffer,
16 sync::atomic::{AtomicBool, AtomicPtr, AtomicUsize, Ordering},
17 utils::Backoff,
18};
19
20pub(crate) struct GrowableQueueCore<T, Q, S = Auto> {
22 cores: [AtomicPtr<Q>; 2],
23 push_epoch: CachePadded<AtomicUsize>,
24 pop_epoch: CachePadded<AtomicUsize>,
25 active_pushes: CachePadded<[AtomicUsize; 2]>,
26 active_reads: CachePadded<[AtomicUsize; 2]>,
27 is_resizing: AtomicBool,
28 _slot: PhantomData<(S, T)>,
29}
30
31impl<T, Q> GrowableQueueCore<T, Q, Auto>
32where
33 Q: NewSized,
34{
35 pub(crate) fn with_slot<S>(size: usize) -> GrowableQueueCore<T, Q, S> {
38 GrowableQueueCore {
39 cores: [
40 AtomicPtr::new(Box::into_raw(Box::new(Q::with_size(size)))),
41 AtomicPtr::new(Box::into_raw(Box::new(Q::with_size(1)))),
42 ],
43 active_pushes: [AtomicUsize::new(0), AtomicUsize::new(0)].into(),
44 active_reads: [AtomicUsize::new(0), AtomicUsize::new(0)].into(),
45 push_epoch: AtomicUsize::new(0).into(),
46 pop_epoch: AtomicUsize::new(0).into(),
47 is_resizing: AtomicBool::new(false),
48 _slot: PhantomData,
49 }
50 }
51}
52
53impl<T, Q, S> Drop for GrowableQueueCore<T, Q, S> {
54 fn drop(&mut self) {
55 let left = self.cores[0].swap(null_mut(), Ordering::Acquire);
56 _ = unsafe { Box::from_raw(left) };
60
61 let right = self.cores[1].swap(null_mut(), Ordering::Acquire);
62 _ = unsafe { Box::from_raw(right) };
66 }
67}
68
69impl<T, Q, S> Resize for GrowableQueueCore<T, Q, S>
70where
71 Q: NewSized + MPMCQueue<Item = T>,
72{
73 fn resize(&self, size: usize) -> bool {
74 if size == 0 {
75 return false;
76 }
77 let pop_epoch = self.pop_epoch.load(Ordering::Acquire);
78 let push_epoch = self.push_epoch.load(Ordering::Acquire);
79
80 if pop_epoch != push_epoch {
81 return false;
82 }
83
84 if self.active_reads[(push_epoch + 1) % 2].load(Ordering::Acquire) != 0 {
85 return false;
87 }
88
89 if self.is_resizing.swap(true, Ordering::AcqRel) {
90 return false;
91 }
92
93 if self.push_epoch.load(Ordering::Acquire) != push_epoch {
94 self.is_resizing.store(false, Ordering::Release);
96 return false;
97 }
98
99 let old_idx = (push_epoch + 1) % 2;
105 let mut backoff = Backoff::new();
106
107 while self.active_reads[old_idx].load(Ordering::Acquire) != 0 {
108 backoff.backoff();
109 }
110
111 debug_assert_eq!(
112 self.active_pushes[(push_epoch + 1) % 2].load(Ordering::SeqCst),
113 0
114 );
115
116 let new_queue = Box::into_raw(Box::new(Q::with_size(size)));
117
118 let old_queue = self.cores[(push_epoch + 1) % 2].swap(new_queue, Ordering::AcqRel);
122 self.push_epoch.fetch_add(1, Ordering::Release);
123
124 let q = unsafe { Box::from_raw(old_queue) };
127
128 debug_assert!(q.pop().is_none());
129
130 self.is_resizing.store(false, Ordering::Release);
131 true
132 }
133}
134
135impl<T, Q, S> GrowableQueueCore<T, Q, S> {
136 fn get_queue(&self, epoch: usize) -> &Q {
137 let queue = self.cores[epoch % 2].load(Ordering::Acquire);
138 unsafe { &*queue }
142 }
143
144 fn register_reader(&self, target_epoch: usize) -> bool {
145 self.active_reads[target_epoch % 2].fetch_add(1, Ordering::Release);
146
147 let current_push = self.push_epoch.load(Ordering::SeqCst);
148 let current_pop = self.pop_epoch.load(Ordering::SeqCst);
149
150 if target_epoch != current_push && target_epoch != current_pop {
152 self.deregister_reader(target_epoch);
153 return false;
154 }
155 true
156 }
157
158 fn deregister_reader(&self, epoch: usize) {
159 self.active_reads[epoch % 2].fetch_sub(1, Ordering::Release);
160 }
161}
162
163impl<T, Q, S> MPMCQueue for GrowableQueueCore<T, Q, S>
164where
165 Q: MPMCQueue<Item = T>,
166{
167 type Item = T;
168
169 fn push(&self, item: Self::Item) -> Result<(), Self::Item> {
170 loop {
171 let push_epoch = self.push_epoch.load(Ordering::Acquire);
172 self.active_pushes[push_epoch % 2].fetch_add(1, Ordering::Release);
173
174 if self.push_epoch.load(Ordering::SeqCst) == push_epoch {
175 let r = self.get_queue(push_epoch).push(item);
176
177 self.active_pushes[push_epoch % 2].fetch_sub(1, Ordering::Release);
178 return r;
179 }
180 self.active_pushes[push_epoch % 2].fetch_sub(1, Ordering::Release);
181 }
182 }
183
184 fn pop(&self) -> Option<Self::Item> {
185 loop {
186 let pop_epoch = self.pop_epoch.load(Ordering::Acquire);
187 let push_epoch = self.push_epoch.load(Ordering::Acquire);
188
189 if pop_epoch != push_epoch {
190 if !self.register_reader(pop_epoch) {
193 continue;
194 }
195
196 let item = self.get_queue(pop_epoch).pop();
198
199 self.deregister_reader(pop_epoch);
200
201 if item.is_some() {
202 return item;
203 }
204
205 if self.active_pushes[pop_epoch % 2].load(Ordering::Acquire) == 0 {
206 if !self.register_reader(pop_epoch) {
207 continue;
208 }
209
210 let final_item = self.get_queue(pop_epoch).pop();
211
212 self.deregister_reader(pop_epoch);
213
214 if final_item.is_some() {
215 return final_item;
216 }
217
218 _ = self.pop_epoch.compare_exchange_weak(
219 pop_epoch,
220 pop_epoch + 1,
221 Ordering::AcqRel,
222 Ordering::Relaxed,
223 );
224 }
225
226 continue;
227 }
228
229 if !self.register_reader(push_epoch) {
230 continue;
231 }
232
233 let item = self.get_queue(push_epoch).pop();
234
235 self.deregister_reader(push_epoch);
236
237 return item;
238 }
239 }
240
241 fn capacity(&self) -> usize {
242 loop {
244 let push_epoch = self.push_epoch.load(Ordering::Acquire);
245 if !self.register_reader(push_epoch) {
246 continue;
247 }
248 let cap = self.get_queue(push_epoch).capacity();
249 self.deregister_reader(push_epoch);
250 return cap;
251 }
252 }
253
254 fn len(&self) -> usize {
255 loop {
257 let push_epoch = self.push_epoch.load(Ordering::Acquire);
258 if !self.register_reader(push_epoch) {
259 continue;
260 }
261
262 let pop_epoch = self.pop_epoch.load(Ordering::Acquire);
263 let pop_len = if pop_epoch != push_epoch {
264 if !self.register_reader(pop_epoch) {
265 self.deregister_reader(push_epoch);
266 continue;
267 }
268
269 let pop_len = self.get_queue(pop_epoch).len();
270 self.deregister_reader(pop_epoch);
271 pop_len
272 } else {
273 0
274 };
275
276 let len = self.get_queue(push_epoch).len() + pop_len;
277 self.deregister_reader(push_epoch);
278 return len;
279 }
280 }
281
282 fn is_empty(&self) -> bool {
283 loop {
285 let push_epoch = self.push_epoch.load(Ordering::Acquire);
286 if !self.register_reader(push_epoch) {
287 continue;
288 }
289
290 let pop_epoch = self.pop_epoch.load(Ordering::Acquire);
291 let pop_is_empty = if pop_epoch != push_epoch {
292 if !self.register_reader(pop_epoch) {
293 self.deregister_reader(push_epoch);
294 continue;
295 }
296
297 let pop_is_empty = self.get_queue(pop_epoch).is_empty();
298 self.deregister_reader(pop_epoch);
299 pop_is_empty
300 } else {
301 true
302 };
303
304 let is_empty = self.get_queue(push_epoch).is_empty() && pop_is_empty;
305 self.deregister_reader(push_epoch);
306 return is_empty;
307 }
308 }
309
310 fn is_full(&self) -> bool {
311 loop {
313 let push_epoch = self.push_epoch.load(Ordering::Acquire);
314 if !self.register_reader(push_epoch) {
315 continue;
316 }
317 let is_full = self.get_queue(push_epoch).is_full();
318 self.deregister_reader(push_epoch);
319
320 return is_full;
321 }
322 }
323}
324
325impl<T, Q, S> NewSized for GrowableQueueCore<T, Q, S>
326where
327 Q: NewSized,
328{
329 fn with_size(size: usize) -> GrowableQueueCore<T, Q, S> {
330 GrowableQueueCore::with_slot(size)
331 }
332}
333
334impl<S> NewSized for QueueCore<BoxedBuffer<S>>
335where
336 S: Default,
337{
338 fn with_size(size: usize) -> Self {
339 Self::new_in(BoxedBuffer::new(size))
340 }
341}
342
343pub struct DynamicQueue<T, S = Auto>
345where
346 S: SlotType<T>,
347 T: AsPackedValue,
348{
349 inner: GrowableQueueCore<T, QueueCore<BoxedBuffer<S::Slot>>, S>,
350}
351
352impl<T> DynamicQueue<T, Auto>
353where
354 T: AsPackedValue,
355{
356 pub fn new(size: usize) -> Self {
359 Self::with_slot::<Auto>(size)
360 }
361
362 pub fn with_slot<S>(size: usize) -> DynamicQueue<T, S>
365 where
366 S: SlotType<T>,
367 {
368 DynamicQueue {
369 inner: GrowableQueueCore::with_slot::<S>(size),
370 }
371 }
372}
373
374impl<T, S> MPMCQueue for DynamicQueue<T, S>
375where
376 T: AsPackedValue,
377 S: SlotType<T>,
378{
379 type Item = T;
380
381 fn push(&self, item: Self::Item) -> Result<(), Self::Item> {
382 self.inner.push(item)
383 }
384
385 fn pop(&self) -> Option<Self::Item> {
386 self.inner.pop()
387 }
388
389 fn len(&self) -> usize {
390 self.inner.len()
391 }
392
393 fn capacity(&self) -> usize {
394 self.inner.capacity()
395 }
396
397 fn is_empty(&self) -> bool {
398 self.inner.is_empty()
399 }
400
401 fn is_full(&self) -> bool {
402 self.inner.is_full()
403 }
404}
405
406impl<T, S> Resize for DynamicQueue<T, S>
407where
408 T: AsPackedValue,
409 S: SlotType<T>,
410{
411 fn resize(&self, size: usize) -> bool {
412 self.inner.resize(size)
413 }
414}