1use std::{
9 collections::VecDeque,
10 fmt,
11 iter::FusedIterator,
12 sync::{Arc, Condvar, Mutex, MutexGuard, PoisonError, TryLockError, atomic::AtomicUsize},
13};
14
15use rand::{Rng, SeedableRng, rngs::SmallRng};
16
17use crate::Priority;
18
19struct PriorityQueues<T> {
20 high_priority: VecDeque<T>,
21 medium_priority: VecDeque<T>,
22 low_priority: VecDeque<T>,
23}
24
25impl<T> PriorityQueues<T> {
26 fn is_empty(&self) -> bool {
27 self.high_priority.is_empty()
28 && self.medium_priority.is_empty()
29 && self.low_priority.is_empty()
30 }
31}
32
33struct PriorityQueueState<T> {
34 queues: Mutex<PriorityQueues<T>>,
37 condvar: Condvar,
38 receiver_count: AtomicUsize,
39 sender_count: AtomicUsize,
40}
41
42impl<T> PriorityQueueState<T> {
43 fn send(&self, priority: Priority, item: T) -> Result<(), SendError<T>> {
44 if self
45 .receiver_count
46 .load(std::sync::atomic::Ordering::Relaxed)
47 == 0
48 {
49 return Err(SendError(item));
50 }
51
52 let mut queues = self.queues.lock().unwrap_or_else(PoisonError::into_inner);
53 Self::push(&mut queues, priority, item);
54 self.condvar.notify_one();
55 Ok(())
56 }
57
58 fn spin_send(&self, priority: Priority, item: T) -> Result<(), SendError<T>> {
59 if self
60 .receiver_count
61 .load(std::sync::atomic::Ordering::Relaxed)
62 == 0
63 {
64 return Err(SendError(item));
65 }
66
67 let mut queues = loop {
68 match self.queues.try_lock() {
69 Ok(guard) => break guard,
70 Err(TryLockError::Poisoned(error)) => break error.into_inner(),
71 Err(TryLockError::WouldBlock) => std::hint::spin_loop(),
72 }
73 };
74 Self::push(&mut queues, priority, item);
75 self.condvar.notify_one();
76 Ok(())
77 }
78
79 fn push(queues: &mut PriorityQueues<T>, priority: Priority, item: T) {
80 match priority {
81 Priority::RealtimeAudio => unreachable!(
82 "Realtime audio priority runs on a dedicated thread and is never queued"
83 ),
84 Priority::High => queues.high_priority.push_back(item),
85 Priority::Medium => queues.medium_priority.push_back(item),
86 Priority::Low => queues.low_priority.push_back(item),
87 };
88 }
89
90 fn recv<'a>(&'a self) -> Result<MutexGuard<'a, PriorityQueues<T>>, RecvError> {
91 let mut queues = self.queues.lock().unwrap_or_else(PoisonError::into_inner);
92
93 while queues.is_empty() {
96 if self.sender_count.load(std::sync::atomic::Ordering::Acquire) == 0 {
97 return Err(crate::queue::RecvError);
98 }
99 queues = self
100 .condvar
101 .wait(queues)
102 .unwrap_or_else(PoisonError::into_inner);
103 }
104
105 Ok(queues)
106 }
107
108 fn try_recv<'a>(&'a self) -> Result<Option<MutexGuard<'a, PriorityQueues<T>>>, RecvError> {
109 let queues = self.queues.lock().unwrap_or_else(PoisonError::into_inner);
110
111 let sender_count = self.sender_count.load(std::sync::atomic::Ordering::Relaxed);
112 if queues.is_empty() && sender_count == 0 {
113 return Err(crate::queue::RecvError);
114 }
115
116 if queues.is_empty() {
117 Ok(None)
118 } else {
119 Ok(Some(queues))
120 }
121 }
122
123 fn spin_try_recv<'a>(&'a self) -> Result<Option<MutexGuard<'a, PriorityQueues<T>>>, RecvError> {
124 let queues = loop {
125 match self.queues.try_lock() {
126 Ok(guard) => break guard,
127 Err(TryLockError::Poisoned(error)) => break error.into_inner(),
128 Err(TryLockError::WouldBlock) => std::hint::spin_loop(),
129 }
130 };
131
132 let sender_count = self.sender_count.load(std::sync::atomic::Ordering::Relaxed);
133 if queues.is_empty() && sender_count == 0 {
134 return Err(crate::queue::RecvError);
135 }
136
137 if queues.is_empty() {
138 Ok(None)
139 } else {
140 Ok(Some(queues))
141 }
142 }
143}
144
145#[doc(hidden)]
150pub struct PriorityQueueSender<T> {
151 state: Arc<PriorityQueueState<T>>,
152}
153
154impl<T> PriorityQueueSender<T> {
155 fn new(state: Arc<PriorityQueueState<T>>) -> Self {
156 Self { state }
157 }
158
159 pub fn send(&self, priority: Priority, item: T) -> Result<(), SendError<T>> {
166 self.state.send(priority, item)?;
167 Ok(())
168 }
169
170 pub fn spin_send(&self, priority: Priority, item: T) -> Result<(), SendError<T>> {
177 self.state.spin_send(priority, item)?;
178 Ok(())
179 }
180}
181
182impl<T> Drop for PriorityQueueSender<T> {
183 fn drop(&mut self) {
184 let previous = self
185 .state
186 .sender_count
187 .fetch_sub(1, std::sync::atomic::Ordering::AcqRel);
188 if previous == 1 {
189 drop(
193 self.state
194 .queues
195 .lock()
196 .unwrap_or_else(PoisonError::into_inner),
197 );
198 self.state.condvar.notify_all();
199 }
200 }
201}
202
203#[doc(hidden)]
208pub struct PriorityQueueReceiver<T> {
209 state: Arc<PriorityQueueState<T>>,
210 rand: SmallRng,
211 disconnected: bool,
212}
213
214impl<T> Clone for PriorityQueueReceiver<T> {
215 fn clone(&self) -> Self {
216 self.state
217 .receiver_count
218 .fetch_add(1, std::sync::atomic::Ordering::AcqRel);
219 Self {
220 state: Arc::clone(&self.state),
221 rand: SmallRng::seed_from_u64(0),
222 disconnected: self.disconnected,
223 }
224 }
225}
226
227#[doc(hidden)]
229pub struct SendError<T>(pub T);
230
231impl<T: fmt::Debug> fmt::Debug for SendError<T> {
232 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
233 f.debug_tuple("SendError").field(&self.0).finish()
234 }
235}
236
237#[derive(Debug)]
239#[doc(hidden)]
240pub struct RecvError;
241
242#[allow(dead_code)]
243impl<T> PriorityQueueReceiver<T> {
244 pub fn new() -> (PriorityQueueSender<T>, Self) {
259 let state = PriorityQueueState {
260 queues: Mutex::new(PriorityQueues {
261 high_priority: VecDeque::new(),
262 medium_priority: VecDeque::new(),
263 low_priority: VecDeque::new(),
264 }),
265 condvar: Condvar::new(),
266 receiver_count: AtomicUsize::new(1),
267 sender_count: AtomicUsize::new(1),
268 };
269 let state = Arc::new(state);
270
271 let sender = PriorityQueueSender::new(Arc::clone(&state));
272
273 let receiver = PriorityQueueReceiver {
274 state,
275 rand: SmallRng::seed_from_u64(0),
276 disconnected: false,
277 };
278
279 (sender, receiver)
280 }
281
282 pub fn is_empty(&self) -> bool {
284 self.state
285 .queues
286 .lock()
287 .unwrap_or_else(PoisonError::into_inner)
288 .is_empty()
289 }
290
291 pub(crate) fn len(&self) -> usize {
293 let queues = self
294 .state
295 .queues
296 .lock()
297 .unwrap_or_else(PoisonError::into_inner);
298 queues.high_priority.len() + queues.medium_priority.len() + queues.low_priority.len()
299 }
300
301 pub fn try_pop(&mut self) -> Result<Option<T>, RecvError> {
309 self.pop_inner(false)
310 }
311
312 pub fn spin_try_pop(&mut self) -> Result<Option<T>, RecvError> {
319 use Priority as P;
320
321 let Some(mut queues) = self.state.spin_try_recv()? else {
322 return Ok(None);
323 };
324
325 let high = P::High.weight() * !queues.high_priority.is_empty() as u32;
326 let medium = P::Medium.weight() * !queues.medium_priority.is_empty() as u32;
327 let low = P::Low.weight() * !queues.low_priority.is_empty() as u32;
328 let mut mass = high + medium + low;
329
330 if !queues.high_priority.is_empty() {
331 let flip = self.rand.random_ratio(P::High.weight(), mass);
332 if flip {
333 return Ok(queues.high_priority.pop_front());
334 }
335 mass -= P::High.weight();
336 }
337
338 if !queues.medium_priority.is_empty() {
339 let flip = self.rand.random_ratio(P::Medium.weight(), mass);
340 if flip {
341 return Ok(queues.medium_priority.pop_front());
342 }
343 mass -= P::Medium.weight();
344 }
345
346 if !queues.low_priority.is_empty() {
347 let flip = self.rand.random_ratio(P::Low.weight(), mass);
348 if flip {
349 return Ok(queues.low_priority.pop_front());
350 }
351 }
352
353 Ok(None)
354 }
355
356 pub fn pop(&mut self) -> Result<T, RecvError> {
364 self.pop_inner(true).map(|e| e.unwrap())
365 }
366
367 pub fn try_iter(self) -> TryIter<T> {
372 TryIter {
373 receiver: self,
374 ended: false,
375 }
376 }
377
378 pub fn iter(self) -> Iter<T> {
384 Iter(self)
385 }
386
387 #[inline(always)]
388 fn pop_inner(&mut self, block: bool) -> Result<Option<T>, RecvError> {
391 use Priority as P;
392
393 let mut queues = if !block {
394 let Some(queues) = self.state.try_recv()? else {
395 return Ok(None);
396 };
397 queues
398 } else {
399 self.state.recv()?
400 };
401
402 let high = P::High.weight() * !queues.high_priority.is_empty() as u32;
403 let medium = P::Medium.weight() * !queues.medium_priority.is_empty() as u32;
404 let low = P::Low.weight() * !queues.low_priority.is_empty() as u32;
405 let mut mass = high + medium + low; if !queues.high_priority.is_empty() {
408 let flip = self.rand.random_ratio(P::High.weight(), mass);
409 if flip {
410 return Ok(queues.high_priority.pop_front());
411 }
412 mass -= P::High.weight();
413 }
414
415 if !queues.medium_priority.is_empty() {
416 let flip = self.rand.random_ratio(P::Medium.weight(), mass);
417 if flip {
418 return Ok(queues.medium_priority.pop_front());
419 }
420 mass -= P::Medium.weight();
421 }
422
423 if !queues.low_priority.is_empty() {
424 let flip = self.rand.random_ratio(P::Low.weight(), mass);
425 if flip {
426 return Ok(queues.low_priority.pop_front());
427 }
428 }
429
430 Ok(None)
431 }
432}
433
434impl<T> Drop for PriorityQueueReceiver<T> {
435 fn drop(&mut self) {
436 self.state
437 .receiver_count
438 .fetch_sub(1, std::sync::atomic::Ordering::AcqRel);
439 }
440}
441
442#[doc(hidden)]
444pub struct Iter<T>(PriorityQueueReceiver<T>);
445impl<T> Iterator for Iter<T> {
446 type Item = T;
447
448 fn next(&mut self) -> Option<Self::Item> {
449 self.0.pop().ok()
450 }
451}
452impl<T> FusedIterator for Iter<T> {}
453
454#[doc(hidden)]
456pub struct TryIter<T> {
457 receiver: PriorityQueueReceiver<T>,
458 ended: bool,
459}
460impl<T> Iterator for TryIter<T> {
461 type Item = Result<T, RecvError>;
462
463 fn next(&mut self) -> Option<Self::Item> {
464 if self.ended {
465 return None;
466 }
467
468 let res = self.receiver.try_pop();
469 self.ended = !matches!(&res, Ok(Some(_)));
470
471 res.transpose()
472 }
473}
474impl<T> FusedIterator for TryIter<T> {}
475
476#[cfg(test)]
477mod tests {
478 use collections::HashSet;
479
480 use super::*;
481
482 #[test]
483 fn dropping_the_last_sender_wakes_a_waiting_receiver() {
484 let (sender, mut receiver) = PriorityQueueReceiver::<usize>::new();
485 let (finished, result) = std::sync::mpsc::channel();
486 std::thread::spawn(move || {
487 finished.send(receiver.pop().is_err()).ok();
488 });
489
490 std::thread::sleep(std::time::Duration::from_millis(100));
491 drop(sender);
492 assert_eq!(
493 result.recv_timeout(std::time::Duration::from_secs(5)),
494 Ok(true)
495 );
496 }
497
498 #[test]
499 fn nonblocking_iterator_stays_finished_after_observing_an_empty_queue() {
500 let (sender, receiver) = PriorityQueueReceiver::new();
501 sender.send(Priority::Medium, 1).unwrap();
502 let mut items = receiver.try_iter();
503 assert!(matches!(items.next(), Some(Ok(1))));
504 assert!(items.next().is_none());
505 sender.send(Priority::High, 2).unwrap();
506 assert!(items.next().is_none());
507 }
508
509 #[test]
510 fn blocked_receivers_end_when_the_sender_drops() {
511 let (sender, receiver) = PriorityQueueReceiver::<u32>::new();
512 let (done_sender, done_receiver) = std::sync::mpsc::channel();
513 let workers = (0..2)
514 .map(|_| {
515 let receiver = receiver.clone();
516 let done_sender = done_sender.clone();
517 std::thread::spawn(move || {
518 let received: Vec<u32> = receiver.iter().collect();
519 done_sender.send(received).ok();
520 })
521 })
522 .collect::<Vec<_>>();
523 drop(receiver);
524
525 sender.send(Priority::Medium, 7).unwrap();
526 std::thread::sleep(std::time::Duration::from_millis(50));
527 assert!(
528 done_receiver.try_recv().is_err(),
529 "receivers keep waiting while the sender is alive"
530 );
531
532 drop(sender);
533 let mut received = Vec::new();
534 for _ in 0..2 {
535 received.extend(
536 done_receiver
537 .recv_timeout(std::time::Duration::from_secs(5))
538 .expect("a waiting receiver should end once the sender is dropped"),
539 );
540 }
541 assert_eq!(received, [7]);
542 for worker in workers {
543 worker.join().expect("worker should exit cleanly");
544 }
545 }
546
547 #[test]
548 fn all_tasks_get_yielded() {
549 let (tx, mut rx) = PriorityQueueReceiver::new();
550 tx.send(Priority::Medium, 20).unwrap();
551 tx.send(Priority::High, 30).unwrap();
552 tx.send(Priority::Low, 10).unwrap();
553 tx.send(Priority::Medium, 21).unwrap();
554 tx.send(Priority::High, 31).unwrap();
555
556 drop(tx);
557
558 assert_eq!(
559 rx.iter().collect::<HashSet<_>>(),
560 [30, 31, 20, 21, 10].into_iter().collect::<HashSet<_>>()
561 )
562 }
563
564 #[test]
565 fn new_high_prio_task_get_scheduled_quickly() {
566 let (tx, mut rx) = PriorityQueueReceiver::new();
567 for _ in 0..100 {
568 tx.send(Priority::Low, 1).unwrap();
569 }
570
571 assert_eq!(rx.pop().unwrap(), 1);
572 tx.send(Priority::High, 3).unwrap();
573 assert_eq!(rx.pop().unwrap(), 3);
574 assert_eq!(rx.pop().unwrap(), 1);
575 }
576}