1use std::cmp::Ordering;
59use std::collections::BTreeMap;
60use std::collections::BTreeSet;
61use std::fmt;
62use std::fmt::Display;
63
64use rand::RngExt as _;
65use rand::SeedableRng;
66use rand::distr::uniform::SampleUniform;
67use rand_pcg::Pcg64Mcg;
68
69use crate::config::SchedHeuristic;
70use crate::detlog;
71use crate::types::DetTid;
72
73pub type Priority = u64;
75
76const EAGER_IO_REPOLL_PRIORITY: Priority = Priority::MIN;
77
78pub const FIRST_PRIORITY: Priority = EAGER_IO_REPOLL_PRIORITY + 1;
80
81pub const LAST_PRIORITY: Priority = 10000;
83
84pub const REPLAY_FOREGROUND_PRIORITY: Priority = FIRST_PRIORITY;
86
87pub const REPLAY_DEFERRED_PRIORITY: Priority = LAST_PRIORITY - 1;
89
90pub const DEFAULT_PRIORITY: Priority = 1000;
93
94pub fn is_ordinary_priority(prio: Priority) -> bool {
97 (FIRST_PRIORITY..=LAST_PRIORITY).contains(&prio)
98}
99
100pub fn entropy_to_priority(entropy: u64) -> Priority {
103 let range = LAST_PRIORITY - FIRST_PRIORITY + 1;
104 let offset = entropy % range;
105 FIRST_PRIORITY + offset
106}
107
108pub const PLAIN_YIELDS_BEFORE_EPOCH: u32 = 1;
116
117type RoundRobinTurn = i64;
121
122#[derive(Debug, Copy, Clone)]
125pub struct PrioritizedOrder {
126 priority: Priority,
127 turn: RoundRobinTurn,
128}
129
130impl Ord for PrioritizedOrder {
132 fn cmp(&self, other: &Self) -> Ordering {
133 self.priority
134 .cmp(&other.priority)
135 .then(self.turn.cmp(&other.turn))
136 }
137}
138impl PartialOrd for PrioritizedOrder {
139 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
140 Some(self.cmp(other))
141 }
142}
143impl PartialEq for PrioritizedOrder {
144 fn eq(&self, other: &Self) -> bool {
145 self.cmp(other).is_eq()
146 }
147}
148impl Eq for PrioritizedOrder {}
149
150impl fmt::Display for PrioritizedOrder {
151 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
152 write!(f, "(p: {}, t: {})", self.priority, self.turn)
153 }
154}
155
156#[derive(Debug, Clone, Copy, PartialEq, Eq)]
158pub enum PollerRestore {
159 Restored,
161 NotBackedOff,
164 NotQueued,
166}
167
168const RUN_TIME_TURNS: RoundRobinTurn = 1 << 61;
171
172pub(crate) const POLLING_UPGRADE_INTERVAL: u64 = 200;
176
177#[derive(Debug, Copy, Clone)]
178struct QueueValue {
179 tid: DetTid,
180 poll_upgrade: Option<Priority>,
182 deadline_restored: bool,
194 upgraded_in_place: bool,
209}
210
211impl QueueValue {
212 fn is_non_polling(&self) -> bool {
216 self.poll_upgrade.is_none() && !self.deadline_restored
217 }
218
219 fn counts_as_poller(&self, priority: Priority) -> bool {
228 self.is_fully_backed_off_poller(priority) || self.deadline_restored
229 }
230
231 fn is_fully_backed_off_poller(&self, priority: Priority) -> bool {
235 self.poll_upgrade.is_some() && priority >= LAST_PRIORITY
236 }
237}
238
239#[derive(Debug, Clone)]
241pub(super) struct SuspendedRunQueueEntry {
242 key: PrioritizedOrder,
243 value: QueueValue,
244 persistent_priority: Priority,
245}
246
247#[derive(Debug, Clone)]
248pub struct RunQueue {
249 queue: BTreeMap<PrioritizedOrder, QueueValue>,
259
260 last_back_turn: RoundRobinTurn,
265 last_front_turn: RoundRobinTurn,
266
267 poll_upgrades: u64,
271
272 tentative_selection: Option<DetTid>,
275 tentative_selection_is_exact: bool,
276
277 yielded_skip: Option<DetTid>,
280
281 yield_epoch: Option<BTreeSet<DetTid>>,
295 yield_streaks: BTreeMap<DetTid, u32>,
301 queued_by_yield: BTreeSet<DetTid>,
307
308 sched_strategy: SchedHeuristic,
311 prng: Pcg64Mcg,
312
313 sticky_random_param: f64,
314 sticky_random_selection: Option<DetTid>,
315}
316
317impl fmt::Display for RunQueue {
319 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
320 writeln!(
321 f,
322 "Run queue, size={}, last_back_turn={}, last_front_turn={}:",
323 self.queue.len(),
324 self.last_back_turn,
325 self.last_front_turn,
326 )?;
327 for x in self.queue.iter() {
328 writeln!(f, " {:.500?}", x)?;
329 }
330 Ok(())
331 }
332}
333
334impl RunQueue {
335 pub fn new(ss: SchedHeuristic, seed: u64, srp: f64) -> Self {
337 detlog!("SCHEDRAND: seeding scheduler runqueue with seed {}", seed);
338 Self {
339 queue: BTreeMap::new(),
340 last_back_turn: 0,
342 last_front_turn: 0,
343 poll_upgrades: 0,
344 sched_strategy: ss,
345 tentative_selection: None,
346 tentative_selection_is_exact: false,
347 yielded_skip: None,
348 yield_epoch: None,
349 yield_streaks: BTreeMap::new(),
350 queued_by_yield: BTreeSet::new(),
351 prng: Pcg64Mcg::seed_from_u64(seed),
352 sticky_random_param: srp,
353 sticky_random_selection: None,
354 }
355 }
356
357 fn push_safety_check(&self, tid: DetTid) {
358 if cfg!(debug_assertions) {
359 for qv in self.queue.values() {
361 if qv.tid == tid {
362 panic!(
363 "Invariant violation! Tried to add {} to runqueue, but it's already present:\n {:?}",
364 tid, self
365 );
366 }
367 }
368 }
369 }
370
371 pub fn has_runnable_besides_unless(
374 &self,
375 exclude: DetTid,
376 passed_over: impl Fn(DetTid) -> bool,
377 ) -> bool {
378 self.queue.iter().any(|(k, v)| {
379 v.tid != exclude && !v.counts_as_poller(k.priority) && !passed_over(v.tid)
380 })
381 }
382
383 pub fn has_runnable_besides(&self, exclude: DetTid) -> bool {
390 self.queue
391 .iter()
392 .any(|(k, v)| v.tid != exclude && !v.counts_as_poller(k.priority))
393 }
394
395 pub fn only_pollers(&self) -> bool {
402 self.queue
403 .iter()
404 .all(|(k, v)| v.counts_as_poller(k.priority))
405 }
406
407 pub fn only_pollers_or_yielders(&self) -> bool {
418 self.queue
419 .iter()
420 .all(|(k, v)| v.counts_as_poller(k.priority) || self.queued_by_yield.contains(&v.tid))
421 }
422
423 pub fn tentative_pop_in_progress(&self) -> bool {
432 self.tentative_selection.is_some()
433 }
434
435 pub fn push_back(&mut self, tid: DetTid, priority: Priority) -> PrioritizedOrder {
440 assert!(self.tentative_selection.is_none());
441 self.push_safety_check(tid);
442 if !is_ordinary_priority(priority) {
443 panic!("This is not an acceptable priority value: {}", priority);
444 }
445 self.push_back_inner(tid, priority, None)
446 }
447
448 pub fn push_yielded(&mut self, tid: DetTid, priority: Priority) -> PrioritizedOrder {
452 assert!(self.yielded_skip.is_none());
453 self.yielded_skip = Some(tid);
454 self.queued_by_yield.insert(tid);
455 self.push_back(tid, priority)
456 }
457
458 pub fn push_yielded_into_epoch(&mut self, tid: DetTid, priority: Priority) -> PrioritizedOrder {
470 let skipped_someone = self.queue.values().any(|value| value.tid != tid);
474 if skipped_someone {
475 let streak = self.yield_streaks.entry(tid).or_insert(0);
476 *streak += 1;
477 if *streak > PLAIN_YIELDS_BEFORE_EPOCH {
478 self.yield_epoch
479 .get_or_insert_with(BTreeSet::new)
480 .insert(tid);
481 }
482 }
483 self.queued_by_yield.insert(tid);
484 self.push_back(tid, priority)
485 }
486
487 pub fn push_poller(
494 &mut self,
495 tid: DetTid,
496 normal_priority: Priority,
497 poll_attempt: u32,
498 ) -> PrioritizedOrder {
499 assert!(self.tentative_selection.is_none());
500 self.push_safety_check(tid);
501 let priority = 1u64
503 .checked_shl(poll_attempt)
504 .and_then(|f| f.checked_mul(normal_priority))
505 .unwrap_or(Priority::MAX)
506 .min(LAST_PRIORITY);
507 self.push_back_inner(tid, priority, Some(normal_priority))
509 }
510
511 fn push_back_inner(
512 &mut self,
513 tid: DetTid,
514 priority: Priority,
515 poll_upgrade: Option<Priority>,
516 ) -> PrioritizedOrder {
517 self.last_back_turn += 1;
518 let turn = self.last_back_turn;
519 let prio = PrioritizedOrder { priority, turn };
520 self.push_inner(tid, prio, poll_upgrade)
521 }
522
523 pub fn push_front(&mut self, tid: DetTid, priority: Priority) -> PrioritizedOrder {
529 assert!(self.tentative_selection.is_none());
530 self.push_safety_check(tid);
531 assert!(is_ordinary_priority(priority));
532 self.push_front_inner(tid, priority, None)
533 }
534
535 pub fn push_eager_io_repoll(&mut self, tid: DetTid) -> PrioritizedOrder {
541 assert!(self.tentative_selection.is_none());
542 self.push_safety_check(tid);
543 let priority = EAGER_IO_REPOLL_PRIORITY;
544 self.push_front_inner(tid, priority, None)
545 }
546
547 fn push_front_inner(
548 &mut self,
549 tid: DetTid,
550 priority: Priority,
551 poll_upgrade: Option<Priority>,
552 ) -> PrioritizedOrder {
553 self.last_front_turn -= 1;
554 let turn = self.last_front_turn;
555 let prio = PrioritizedOrder { priority, turn };
556 self.push_inner(tid, prio, poll_upgrade)
557 }
558
559 fn push_inner(
560 &mut self,
561 tid: DetTid,
562 prio: PrioritizedOrder,
563 poll_upgrade: Option<Priority>,
564 ) -> PrioritizedOrder {
565 let qval = QueueValue {
566 tid,
567 poll_upgrade,
568 deadline_restored: false,
569 upgraded_in_place: false,
570 };
571 let old = self.queue.insert(prio, qval);
572 assert!(old.is_none()); self.check_poll_upgrade();
574 prio
575 }
576
577 pub fn is_empty(&self) -> bool {
579 self.queue.is_empty()
580 }
581
582 pub fn len(&self) -> usize {
584 self.queue.len()
585 }
586
587 pub fn tids(&self) -> impl Iterator<Item = &DetTid> {
589 self.queue.values().map(|v| &v.tid)
590 }
591
592 pub fn contains_tid(&self, tid: DetTid) -> bool {
594 self.tids().any(|t| t == &tid)
595 }
596
597 pub fn contains_non_polling_tid(&self, tid: DetTid) -> bool {
604 self.queue
605 .iter()
606 .any(|(_, v)| v.tid == tid && v.is_non_polling())
607 }
608
609 pub fn can_be_passed_over(&self, tid: DetTid) -> bool {
617 self.queue
618 .values()
619 .any(|v| v.tid == tid && (v.is_non_polling() || v.upgraded_in_place))
620 }
621
622 pub(super) fn suspend(
623 &mut self,
624 tid: DetTid,
625 persistent_priority: Priority,
626 ) -> Option<SuspendedRunQueueEntry> {
627 assert!(self.tentative_selection.is_none());
628 let key = *self.queue.iter().find(|(_, v)| v.tid == tid)?.0;
629 let value = self.queue.remove(&key).expect("located queue entry");
630 Some(SuspendedRunQueueEntry {
631 key,
632 value,
633 persistent_priority,
634 })
635 }
636
637 pub(super) fn restore(
638 &mut self,
639 mut entry: SuspendedRunQueueEntry,
640 current_priority: Priority,
641 ) {
642 assert!(self.tentative_selection.is_none());
643 assert!(!self.contains_tid(entry.value.tid));
644 if entry.persistent_priority != current_priority {
645 entry.key.priority = current_priority;
646 if entry.value.poll_upgrade.is_some() {
647 entry.value.poll_upgrade = Some(current_priority);
648 }
649 }
650 if entry.key.turn >= RUN_TIME_TURNS {
654 while self.queue.contains_key(&entry.key) {
655 entry.key.turn += 1;
656 }
657 }
658 assert!(self.queue.insert(entry.key, entry.value).is_none());
659 }
660
661 fn in_round_robin_order(key: &PrioritizedOrder, value: &QueueValue) -> bool {
666 key.turn >= 0
667 && key.priority != EAGER_IO_REPOLL_PRIORITY
668 && value.poll_upgrade.is_none()
669 && !value.deadline_restored
670 }
671
672 pub(super) fn round_robin_tids(&self) -> Vec<DetTid> {
675 let mut tids: Vec<DetTid> = self
676 .queue
677 .iter()
678 .filter(|(key, value)| Self::in_round_robin_order(key, value))
679 .map(|(_, value)| value.tid)
680 .collect();
681 tids.sort();
682 tids
683 }
684
685 pub(super) fn order_by_run_time(&mut self, order: &[(DetTid, (u64, u64))]) {
692 assert!(self.tentative_selection.is_none());
693 let wanted: BTreeMap<DetTid, (u64, u64)> = order.iter().copied().collect();
694 let keys: Vec<PrioritizedOrder> = self
695 .queue
696 .iter()
697 .filter(|(key, value)| {
698 wanted.contains_key(&value.tid) && Self::in_round_robin_order(key, value)
699 })
700 .map(|(key, _)| *key)
701 .collect();
702 let mut moved: Vec<(Priority, (u64, u64), QueueValue)> = keys
703 .into_iter()
704 .map(|key| {
705 let value = self.queue.remove(&key).expect("located queue entry");
706 (key.priority, wanted[&value.tid], value)
707 })
708 .collect();
709 moved.sort_by_key(|(priority, sort_key, value)| (*priority, *sort_key, value.tid));
710 let mut last: Option<PrioritizedOrder> = None;
714 for (priority, (run_time, _), value) in moved {
715 let offset = RoundRobinTurn::try_from(run_time).unwrap_or(RoundRobinTurn::MAX);
716 let mut turn = RUN_TIME_TURNS.saturating_add(offset.min(RUN_TIME_TURNS));
717 if let Some(previous) = last
718 && previous.priority == priority
719 {
720 turn = turn.max(previous.turn + 1);
721 }
722 let mut key = PrioritizedOrder { priority, turn };
723 while self.queue.contains_key(&key) {
724 key.turn += 1;
725 }
726 assert!(self.queue.insert(key, value).is_none());
727 last = Some(key);
728 }
729 }
730
731 pub fn remove_tid(&mut self, tid: DetTid) -> bool {
734 assert!(self.tentative_selection.is_none());
735
736 let mut kept_all = true;
738 self.queue.retain(|_k, v| {
739 let ret = v.tid != tid;
740 kept_all = kept_all && ret;
741 ret
742 });
743 if self.yielded_skip == Some(tid) {
744 self.yielded_skip = None;
745 }
746 if let Some(epoch) = &mut self.yield_epoch {
747 epoch.remove(&tid);
748 }
749 self.yield_streaks.remove(&tid);
750 self.queued_by_yield.remove(&tid);
751 if self.sticky_random_selection == Some(tid) {
756 self.sticky_random_selection = None;
757 }
758 !kept_all
759 }
760
761 fn random_range<T>(&mut self, start: T, end: T) -> T
763 where
764 T: SampleUniform + Display + PartialOrd + Copy,
765 {
766 let r = self.prng.random_range(start..end);
767 detlog!("SCHEDRAND: [{},{}) => {}", start, end, r);
768 r
769 }
770
771 pub fn tentative_pop_next(&mut self) -> Option<DetTid> {
777 assert!(!self.tentative_selection_is_exact);
778 let skip = self
779 .yielded_skip
780 .filter(|tid| self.queue.len() > 1 && self.contains_tid(*tid));
781 if self.yield_epoch.as_ref().is_some_and(|epoch| {
788 self.queue.iter().all(|(key, value)| {
789 epoch.contains(&value.tid) || value.is_fully_backed_off_poller(key.priority)
790 })
791 }) {
792 self.end_yield_epoch();
793 }
794 let mut excluded: BTreeSet<DetTid> = skip.into_iter().collect();
795 if let Some(epoch) = &self.yield_epoch {
796 let with_epoch: BTreeSet<DetTid> = excluded.union(epoch).copied().collect();
797 if self
800 .queue
801 .values()
802 .any(|value| !with_epoch.contains(&value.tid))
803 {
804 excluded = with_epoch;
805 }
806 }
807 let excluded_count = self
808 .queue
809 .values()
810 .filter(|value| excluded.contains(&value.tid))
811 .count();
812 self.tentative_selection = match self.sched_strategy {
813 SchedHeuristic::None | SchedHeuristic::ConnectBind => self
814 .queue
815 .values()
816 .find(|value| !excluded.contains(&value.tid))
817 .map(|value| value.tid),
818 SchedHeuristic::Random => {
819 if self.queue.is_empty() {
820 return None;
821 }
822
823 if self.tentative_selection.is_none() {
825 let eligible = self.queue.len() - excluded_count;
826 let random_idx = self.random_range(0, eligible);
827 self.tentative_selection = self
828 .queue
829 .values()
830 .filter(|value| !excluded.contains(&value.tid))
831 .nth(random_idx)
832 .map(|value| value.tid);
833 };
834
835 self.tentative_selection
836 }
837 SchedHeuristic::StickyRandom => {
838 if self.queue.is_empty() {
839 return None;
840 }
841
842 if self
843 .sticky_random_selection
844 .is_some_and(|tid| excluded.contains(&tid))
845 {
846 self.sticky_random_selection = None;
847 }
848 if self.sticky_random_selection.is_none()
849 || !self.contains_tid(self.sticky_random_selection.unwrap())
850 {
851 let eligible = self.queue.len() - excluded_count;
852 let random_idx = self.random_range(0, eligible);
853 self.sticky_random_selection = self
854 .queue
855 .values()
856 .filter(|value| !excluded.contains(&value.tid))
857 .nth(random_idx)
858 .map(|value| value.tid);
859 }
860
861 self.sticky_random_selection
862 }
863 };
864
865 self.tentative_selection
866 }
867
868 pub fn tentative_pop_tid(&mut self, tid: DetTid) -> Option<DetTid> {
872 assert!(self.tentative_selection.is_none());
873 if self.contains_tid(tid) {
874 self.tentative_selection = Some(tid);
875 self.tentative_selection_is_exact = true;
876 }
877 self.tentative_selection
878 }
879
880 pub fn commit_tentative_pop(&mut self) -> DetTid {
887 self.commit_selection()
888 }
889
890 pub fn end_yield_epoch(&mut self) {
892 self.yield_epoch = None;
893 self.yield_streaks.clear();
894 }
895
896 pub fn commit_tentative_pop_yield(&mut self) -> DetTid {
900 let tid = self.commit_selection();
901 self.consume_yield_exclusion();
902 tid
903 }
904
905 fn commit_selection(&mut self) -> DetTid {
906 let tentative_selection = self
908 .tentative_selection
909 .take()
910 .expect("tentative_pop to already returned a `Some`");
911 let exact = std::mem::take(&mut self.tentative_selection_is_exact);
912
913 let ret = if exact {
914 let key = *self
915 .queue
916 .iter()
917 .find(|(_key, value)| value.tid == tentative_selection)
918 .map(|(key, _value)| key)
919 .unwrap();
920 self.queue.remove(&key).map(|value| value.tid)
921 } else {
922 match self.sched_strategy {
923 SchedHeuristic::None | SchedHeuristic::ConnectBind | SchedHeuristic::Random => {
924 let key = *self
925 .queue
926 .iter()
927 .find(|(_k, v)| v.tid == tentative_selection)
928 .map(|(k, _v)| k)
929 .unwrap();
930 self.queue.remove(&key).map(|v| v.tid)
931 }
932 SchedHeuristic::StickyRandom => {
933 let tid = self.sticky_random_selection.unwrap();
934 if self.random_range(0f64, 1f64) <= 1.0 - self.sticky_random_param {
937 self.sticky_random_selection = None;
938 }
939
940 let key = *self
941 .queue
942 .iter()
943 .find(|(_k, v)| v.tid == tid)
944 .map(|(k, _v)| k)
945 .unwrap();
946
947 self.queue.remove(&key).map(|v| v.tid)
948 }
949 }
950 }
951 .expect("to always return a DetTid");
952 debug_assert!(ret == tentative_selection);
956 self.queued_by_yield.remove(&ret);
957 ret
958 }
959
960 pub fn commit_tentative_pop_completed_turn(&mut self) -> DetTid {
964 let tid = self.commit_tentative_pop();
965 self.consume_yield_exclusion();
966 self.end_yield_epoch();
972 tid
973 }
974
975 pub fn consume_yield_exclusion(&mut self) {
977 self.yielded_skip = None;
978 }
979
980 pub fn undo_tentative_pop(&mut self) {
982 assert!(self.tentative_selection.is_some());
983 self.tentative_selection = None;
984 self.tentative_selection_is_exact = false;
985 }
986
987 fn turn_counter(&self) -> u64 {
989 debug_assert!(self.last_back_turn >= 0);
990 debug_assert!(self.last_front_turn <= 0);
991 self.last_back_turn as u64 + self.last_front_turn.unsigned_abs()
992 }
993
994 fn check_poll_upgrade(&mut self) {
995 if self.turn_counter().is_multiple_of(POLLING_UPGRADE_INTERVAL) {
996 self.do_poll_upgrade();
997 }
998 }
999
1000 pub fn is_priority_ordered(&self) -> bool {
1003 self.sched_strategy.is_priority_ordered()
1004 }
1005
1006 #[cfg(test)]
1008 pub fn poll_upgrade_now(&mut self) {
1009 self.do_poll_upgrade();
1010 }
1011
1012 #[cfg(test)]
1014 pub fn queued_priority(&self, tid: DetTid) -> Option<Priority> {
1015 self.queue
1016 .iter()
1017 .find(|(_, value)| value.tid == tid)
1018 .map(|(key, _)| key.priority)
1019 }
1020
1021 pub fn restore_poller_priority(&mut self, tid: DetTid) -> PollerRestore {
1037 assert!(self.tentative_selection.is_none());
1038 let Some((&key, value)) = self.queue.iter().find(|(_, value)| value.tid == tid) else {
1039 return PollerRestore::NotQueued;
1040 };
1041 let Some(normal_priority) = value.poll_upgrade else {
1042 return PollerRestore::NotBackedOff;
1043 };
1044 let mut value = self.queue.remove(&key).expect("located queue entry");
1045 value.poll_upgrade = None;
1046 value.deadline_restored = key.priority >= LAST_PRIORITY;
1049 self.last_back_turn += 1;
1050 let restored = PrioritizedOrder {
1051 priority: normal_priority,
1052 turn: self.last_back_turn,
1053 };
1054 assert!(self.queue.insert(restored, value).is_none());
1055 self.check_poll_upgrade();
1056 PollerRestore::Restored
1057 }
1058
1059 pub fn poll_upgrade_count(&self) -> u64 {
1061 self.poll_upgrades
1062 }
1063
1064 pub fn upgrade_pollers(&mut self) -> Vec<DetTid> {
1071 assert!(self.tentative_selection.is_none());
1072 self.do_poll_upgrade()
1073 }
1074
1075 #[cold]
1078 fn do_poll_upgrade(&mut self) -> Vec<DetTid> {
1079 self.poll_upgrades += 1;
1080 let upgrades = self
1081 .queue
1082 .iter()
1083 .filter_map(|(k, v)| v.poll_upgrade.map(|upgd| (*k, upgd)))
1084 .collect::<Vec<(PrioritizedOrder, Priority)>>();
1085 let mut restored = Vec::new();
1089 for (key, upgrade_prio) in upgrades {
1090 if upgrade_prio >= LAST_PRIORITY {
1100 self.queue
1101 .get_mut(&key)
1102 .expect("located queue entry")
1103 .upgraded_in_place = true;
1104 continue;
1105 }
1106 let mut new_key = key;
1107 new_key.priority = upgrade_prio;
1108 let mut qval = self.queue.remove(&key).unwrap();
1109 qval.poll_upgrade = None; restored.push(qval.tid);
1111 let old = self.queue.insert(new_key, qval);
1112 assert!(old.is_none()); }
1114 for (key, value) in self.queue.iter_mut() {
1121 if key.priority < LAST_PRIORITY {
1122 value.deadline_restored = false;
1123 } else if value.deadline_restored {
1124 value.upgraded_in_place = true;
1125 }
1126 }
1127 restored
1128 }
1129}
1130
1131impl Default for RunQueue {
1132 fn default() -> Self {
1133 Self::new(SchedHeuristic::None, 0, 0.0)
1134 }
1135}
1136
1137#[cfg(test)]
1138mod tests {
1139 use super::*;
1140
1141 #[test]
1145 fn a_restored_entry_ordered_by_run_time_takes_the_next_free_turn() {
1146 let mut queue = RunQueue::new(SchedHeuristic::None, 0, 0.0);
1147 let (first, second) = (DetTid::from_raw(3), DetTid::from_raw(5));
1148 queue.push_back(first, DEFAULT_PRIORITY);
1149 queue.push_back(second, DEFAULT_PRIORITY);
1150 queue.order_by_run_time(&[(first, (5, 0)), (second, (9, 0))]);
1151 let suspended = queue.suspend(first, DEFAULT_PRIORITY).expect("queued");
1152 queue.order_by_run_time(&[(second, (5, 0))]);
1153 queue.restore(suspended, DEFAULT_PRIORITY);
1154 assert_eq!(queue.tentative_pop_next(), Some(second));
1155 queue.commit_tentative_pop();
1156 assert_eq!(queue.tentative_pop_next(), Some(first));
1157 }
1158
1159 #[test]
1165 fn restore_poller_priority_moves_one_poller_to_the_back_of_its_level() {
1166 let poller = DetTid::from_raw(1);
1167 let other = DetTid::from_raw(2);
1168 let spinner = DetTid::from_raw(3);
1169 let mut queue = RunQueue::new(SchedHeuristic::None, 0, 0.0);
1170 queue.push_poller(poller, DEFAULT_PRIORITY, 3);
1171 queue.push_poller(other, DEFAULT_PRIORITY, 3);
1172 queue.push_back(spinner, DEFAULT_PRIORITY);
1173 let pushes = queue.turn_counter();
1174 assert_eq!(queue.tentative_pop_next(), Some(spinner));
1176 queue.undo_tentative_pop();
1177
1178 assert_eq!(
1179 queue.restore_poller_priority(poller),
1180 PollerRestore::Restored
1181 );
1182 assert_eq!(queue.turn_counter(), pushes + 1, "a restore is one push");
1183 assert_eq!(queue.queued_priority(poller), Some(DEFAULT_PRIORITY));
1184 assert_eq!(queue.tentative_pop_next(), Some(spinner), "queued first");
1185 assert_eq!(queue.commit_tentative_pop(), spinner);
1186 queue.push_back(spinner, DEFAULT_PRIORITY);
1187 assert_eq!(
1188 queue.tentative_pop_next(),
1189 Some(poller),
1190 "ahead of the requeue"
1191 );
1192 queue.undo_tentative_pop();
1193 let (other_key, other_value) = queue
1194 .queue
1195 .iter()
1196 .find(|(_, value)| value.tid == other)
1197 .unwrap();
1198 assert_eq!(other_key.priority, 8 * DEFAULT_PRIORITY);
1199 assert_eq!(other_value.poll_upgrade, Some(DEFAULT_PRIORITY));
1200
1201 assert_eq!(
1202 queue.restore_poller_priority(poller),
1203 PollerRestore::NotBackedOff
1204 );
1205 assert_eq!(
1206 queue.restore_poller_priority(spinner),
1207 PollerRestore::NotBackedOff
1208 );
1209 assert_eq!(
1210 queue.restore_poller_priority(DetTid::from_raw(9)),
1211 PollerRestore::NotQueued
1212 );
1213 }
1214
1215 #[test]
1220 fn an_ordinary_thread_in_the_last_band_is_not_a_poller() {
1221 let worker = DetTid::from_raw(1);
1222 let poller = DetTid::from_raw(2);
1223 let other = DetTid::from_raw(3);
1224
1225 let mut queue = RunQueue::new(SchedHeuristic::None, 0, 0.0);
1226 queue.push_back(worker, LAST_PRIORITY);
1227 assert!(!queue.only_pollers());
1228 assert!(!queue.only_pollers_or_yielders());
1229 assert!(queue.has_runnable_besides(other));
1230
1231 let mut queue = RunQueue::new(SchedHeuristic::None, 0, 0.0);
1232 queue.push_poller(poller, DEFAULT_PRIORITY, u32::MAX);
1233 assert!(
1234 queue.only_pollers(),
1235 "a fully backed-off poller is a poller"
1236 );
1237 assert!(!queue.has_runnable_besides(other));
1238 queue.push_back(worker, LAST_PRIORITY);
1239 assert!(
1240 !queue.only_pollers(),
1241 "the ordinary thread beside it is work"
1242 );
1243 assert!(queue.has_runnable_besides(poller));
1244 }
1245
1246 #[test]
1252 fn a_deadline_restored_poller_counts_as_a_poller_until_it_runs() {
1253 let poller = DetTid::from_raw(1);
1254 let other = DetTid::from_raw(2);
1255 let mut queue = RunQueue::new(SchedHeuristic::None, 0, 0.0);
1256 queue.push_poller(poller, DEFAULT_PRIORITY, 30);
1257 assert!(queue.only_pollers());
1258 assert_eq!(
1259 queue.restore_poller_priority(poller),
1260 PollerRestore::Restored
1261 );
1262 assert!(queue.only_pollers(), "restored, but it has not run");
1263 assert!(!queue.has_runnable_besides(other));
1264
1265 assert_eq!(queue.tentative_pop_next(), Some(poller));
1266 assert_eq!(queue.commit_tentative_pop(), poller);
1267 queue.push_back(poller, DEFAULT_PRIORITY);
1268 assert!(!queue.only_pollers(), "after its turn it is ordinary work");
1269 assert!(queue.has_runnable_besides(other));
1270
1271 let mut queue = RunQueue::new(SchedHeuristic::None, 0, 0.0);
1272 queue.push_poller(poller, DEFAULT_PRIORITY, 1);
1273 assert!(
1274 !queue.only_pollers(),
1275 "at 2000 it is ordinary work, as on main"
1276 );
1277 assert_eq!(
1278 queue.restore_poller_priority(poller),
1279 PollerRestore::Restored
1280 );
1281 assert!(!queue.only_pollers(), "and stays so after the restore");
1282 assert!(queue.has_runnable_besides(other));
1283 }
1284
1285 #[test]
1289 fn a_poll_upgrade_ends_a_restored_pollers_poller_status() {
1290 let poller = DetTid::from_raw(1);
1291 let mut queue = RunQueue::new(SchedHeuristic::None, 0, 0.0);
1292 queue.push_poller(poller, DEFAULT_PRIORITY, 30);
1293 assert_eq!(
1294 queue.restore_poller_priority(poller),
1295 PollerRestore::Restored
1296 );
1297 assert!(queue.only_pollers());
1298 queue.do_poll_upgrade();
1299 assert!(
1300 !queue.only_pollers(),
1301 "upgraded like every backed-off poller"
1302 );
1303 }
1304
1305 #[test]
1312 fn a_last_band_pollers_upgrade_keeps_it_a_poller() {
1313 let poller = DetTid::from_raw(1);
1314 let mut queue = RunQueue::default();
1315 queue.push_poller(poller, LAST_PRIORITY, 0);
1316 assert!(queue.only_pollers());
1317 queue.do_poll_upgrade();
1318 assert!(
1319 queue.only_pollers(),
1320 "an upgrade to the same band is a no-op"
1321 );
1322 assert_eq!(queue.queued_priority(poller), Some(LAST_PRIORITY));
1323
1324 let restored = DetTid::from_raw(2);
1325 let mut queue = RunQueue::default();
1326 queue.push_poller(restored, LAST_PRIORITY, 3);
1327 assert_eq!(
1328 queue.restore_poller_priority(restored),
1329 PollerRestore::Restored
1330 );
1331 queue.do_poll_upgrade();
1332 assert!(
1333 queue.only_pollers(),
1334 "so is one its deadline restored there"
1335 );
1336
1337 let count = POLLING_UPGRADE_INTERVAL as i32;
1338 let mut queue = RunQueue::default();
1339 for raw in 1..=count {
1340 queue.push_poller(DetTid::from_raw(raw), LAST_PRIORITY, 0);
1341 }
1342 for cycle in 0..20 * count {
1343 assert!(queue.only_pollers(), "cycle {cycle}");
1344 let tid = queue.tentative_pop_next().expect("a queued poller");
1345 assert_eq!(queue.commit_tentative_pop(), tid);
1346 queue.push_poller(tid, LAST_PRIORITY, 1);
1347 }
1348 assert!(queue.only_pollers());
1349 }
1350
1351 #[test]
1359 fn a_poll_upgrade_lets_the_change_point_bound_count_a_last_band_poller() {
1360 let poller = DetTid::from_raw(1);
1361 let other = DetTid::from_raw(2);
1362 let mut queue = RunQueue::default();
1363 queue.push_poller(poller, LAST_PRIORITY, 5);
1364 queue.push_poller(other, DEFAULT_PRIORITY, 30);
1365 assert!(!queue.can_be_passed_over(poller), "backed off: not yet");
1366 assert!(!queue.can_be_passed_over(other));
1367 queue.do_poll_upgrade();
1368 assert!(queue.can_be_passed_over(poller), "the upgrade reached it");
1369 assert!(queue.can_be_passed_over(other), "moved, as on main");
1370 assert!(!queue.contains_non_polling_tid(poller));
1371 assert_eq!(queue.queued_priority(poller), Some(LAST_PRIORITY));
1372 assert!(queue.remove_tid(other));
1373 assert!(queue.only_pollers(), "still a poller for the gates");
1374 assert!(!queue.has_runnable_besides(other));
1375
1376 assert_eq!(queue.tentative_pop_next(), Some(poller));
1377 assert_eq!(queue.commit_tentative_pop(), poller);
1378 queue.push_poller(poller, LAST_PRIORITY, 6);
1379 assert!(!queue.can_be_passed_over(poller), "requeued: backed off");
1380
1381 let restored = DetTid::from_raw(3);
1382 let mut queue = RunQueue::default();
1383 queue.push_poller(restored, LAST_PRIORITY, 3);
1384 assert_eq!(
1385 queue.restore_poller_priority(restored),
1386 PollerRestore::Restored
1387 );
1388 assert!(!queue.can_be_passed_over(restored));
1389 queue.do_poll_upgrade();
1390 assert!(queue.can_be_passed_over(restored));
1391 assert!(queue.only_pollers());
1392 assert!(!queue.contains_tid(DetTid::from_raw(9)));
1393 assert!(!queue.can_be_passed_over(DetTid::from_raw(9)));
1394 }
1395
1396 #[test]
1399 fn a_chaos_yield_marks_its_thread_as_a_yielder() {
1400 let yielder = DetTid::from_raw(1);
1401 let other = DetTid::from_raw(2);
1402 let mut queue = RunQueue::default();
1403 queue.push_back(yielder, LAST_PRIORITY);
1404 yield_turn(&mut queue, yielder, LAST_PRIORITY);
1405 assert!(!queue.only_pollers(), "a yielder is not a poller");
1406 assert!(queue.only_pollers_or_yielders());
1407 queue.push_back(other, DEFAULT_PRIORITY);
1408 assert!(!queue.only_pollers_or_yielders());
1409 assert!(queue.remove_tid(other));
1410 assert_eq!(take_turn(&mut queue), yielder);
1411 queue.push_back(yielder, LAST_PRIORITY);
1412 assert!(!queue.only_pollers_or_yielders(), "it ran without yielding");
1413 }
1414
1415 #[test]
1416 fn only_first_entry_heuristics_are_priority_ordered() {
1417 for (strategy, ordered) in [
1418 (SchedHeuristic::None, true),
1419 (SchedHeuristic::ConnectBind, true),
1420 (SchedHeuristic::Random, false),
1421 (SchedHeuristic::StickyRandom, false),
1422 ] {
1423 assert_eq!(
1424 RunQueue::new(strategy, 0, 0.5).is_priority_ordered(),
1425 ordered,
1426 "{strategy:?}"
1427 );
1428 }
1429 }
1430
1431 #[test]
1432 fn transport_suspend_restore_preserves_all_queue_state() {
1433 for strategy in [
1434 SchedHeuristic::None,
1435 SchedHeuristic::Random,
1436 SchedHeuristic::StickyRandom,
1437 ] {
1438 let tid = DetTid::from_raw(1);
1439 let peer = DetTid::from_raw(2);
1440 let mut queue = RunQueue::new(strategy, 391, 0.5);
1441 queue.push_yielded(tid, DEFAULT_PRIORITY);
1442 queue.push_back(peer, DEFAULT_PRIORITY);
1443 let key = *queue
1444 .queue
1445 .iter()
1446 .find(|(_, value)| value.tid == tid)
1447 .unwrap()
1448 .0;
1449 queue.queue.get_mut(&key).unwrap().poll_upgrade = Some(DEFAULT_PRIORITY);
1450 queue.sticky_random_selection = Some(tid);
1451 let before = format!("{queue:?}");
1452 let saved = queue.suspend(tid, DEFAULT_PRIORITY).unwrap();
1453 assert_eq!(queue.yielded_skip, Some(tid));
1454 assert_eq!(queue.sticky_random_selection, Some(tid));
1455 queue.restore(saved, DEFAULT_PRIORITY);
1456 assert_eq!(format!("{queue:?}"), before, "{strategy:?}");
1457 }
1458 }
1459
1460 #[test]
1461 fn observation_restore_keeps_real_selection_progress_and_new_priority() {
1462 for strategy in [
1463 SchedHeuristic::None,
1464 SchedHeuristic::Random,
1465 SchedHeuristic::StickyRandom,
1466 ] {
1467 let tid = DetTid::from_raw(1);
1468 let peer = DetTid::from_raw(2);
1469 let mut queue = RunQueue::new(strategy, 391, 0.5);
1470 queue.push_yielded(tid, DEFAULT_PRIORITY);
1471 queue.push_back(peer, DEFAULT_PRIORITY);
1472 let key = *queue
1473 .queue
1474 .iter()
1475 .find(|(_, value)| value.tid == tid)
1476 .unwrap()
1477 .0;
1478 queue.queue.get_mut(&key).unwrap().poll_upgrade = Some(DEFAULT_PRIORITY);
1479 let saved = queue.suspend(tid, DEFAULT_PRIORITY).unwrap();
1480 assert_eq!(queue.tentative_pop_next(), Some(peer));
1481 assert_eq!(queue.commit_tentative_pop_completed_turn(), peer);
1482 assert_eq!(queue.yielded_skip, None);
1483 queue.push_back(peer, DEFAULT_PRIORITY);
1484 let random_after_turn = format!("{:?}", queue.prng);
1485 let sticky_after_turn = queue.sticky_random_selection;
1486 let turns_after_turn = (queue.last_back_turn, queue.last_front_turn);
1487 queue.restore(saved, DEFAULT_PRIORITY + 3);
1488 let (restored, value) = queue
1489 .queue
1490 .iter()
1491 .find(|(_, value)| value.tid == tid)
1492 .unwrap();
1493 assert_eq!(restored.turn, key.turn);
1494 assert_eq!(restored.priority, DEFAULT_PRIORITY + 3);
1495 assert_eq!(value.poll_upgrade, Some(DEFAULT_PRIORITY + 3));
1496 assert_eq!(queue.yielded_skip, None);
1497 assert_eq!(queue.sticky_random_selection, sticky_after_turn);
1498 assert_eq!(
1499 (queue.last_back_turn, queue.last_front_turn),
1500 turns_after_turn
1501 );
1502 assert_eq!(format!("{:?}", queue.prng), random_after_turn);
1503 }
1504 }
1505
1506 #[test]
1507 fn yielded_thread_cedes_exactly_one_turn_under_every_heuristic() {
1508 for strategy in [
1509 SchedHeuristic::None,
1510 SchedHeuristic::ConnectBind,
1511 SchedHeuristic::Random,
1512 SchedHeuristic::StickyRandom,
1513 ] {
1514 let yielding = DetTid::from_raw(1);
1515 let peer = DetTid::from_raw(2);
1516 let mut queue = RunQueue::new(strategy, 0, 1.0);
1517
1518 queue.push_back(yielding, DEFAULT_PRIORITY - 1);
1519 assert_eq!(queue.tentative_pop_next(), Some(yielding));
1520 assert_eq!(queue.commit_tentative_pop(), yielding);
1521
1522 queue.push_yielded(yielding, DEFAULT_PRIORITY - 1);
1523 queue.push_back(peer, LAST_PRIORITY);
1524 assert_eq!(queue.tentative_pop_next(), Some(peer), "{strategy:?}");
1525 assert_eq!(
1526 queue.commit_tentative_pop_completed_turn(),
1527 peer,
1528 "{strategy:?}"
1529 );
1530
1531 assert_eq!(queue.yielded_skip, None, "{strategy:?}");
1532 let restored_priority = queue
1533 .queue
1534 .iter()
1535 .find(|(_key, value)| value.tid == yielding)
1536 .map(|(key, _value)| key.priority);
1537 assert_eq!(
1538 restored_priority,
1539 Some(DEFAULT_PRIORITY - 1),
1540 "{strategy:?}"
1541 );
1542
1543 if matches!(strategy, SchedHeuristic::None | SchedHeuristic::ConnectBind) {
1544 queue.push_back(peer, LAST_PRIORITY);
1545 assert_eq!(queue.tentative_pop_next(), Some(yielding), "{strategy:?}");
1546 }
1547 }
1548 }
1549
1550 #[test]
1551 fn exact_selection_bypasses_priority_and_heuristic() {
1552 for strategy in [
1553 SchedHeuristic::None,
1554 SchedHeuristic::ConnectBind,
1555 SchedHeuristic::Random,
1556 SchedHeuristic::StickyRandom,
1557 ] {
1558 let higher_priority = DetTid::from_raw(1);
1559 let selected = DetTid::from_raw(2);
1560 let mut queue = RunQueue::new(strategy, 0, 1.0);
1561 queue.push_back(higher_priority, FIRST_PRIORITY);
1562 queue.push_back(selected, LAST_PRIORITY);
1563
1564 assert_eq!(queue.tentative_pop_tid(selected), Some(selected));
1565 assert_eq!(queue.commit_tentative_pop(), selected);
1566 assert!(queue.contains_tid(higher_priority));
1567 assert!(!queue.contains_tid(selected));
1568 }
1569 }
1570
1571 #[test]
1572 fn scheduler_only_commit_does_not_consume_yield_exclusion() {
1573 let yielding = DetTid::from_raw(1);
1574 let peer = DetTid::from_raw(2);
1575 let mut queue = RunQueue::default();
1576
1577 queue.push_back(yielding, DEFAULT_PRIORITY);
1578 assert_eq!(queue.tentative_pop_next(), Some(yielding));
1579 assert_eq!(queue.commit_tentative_pop(), yielding);
1580
1581 queue.push_yielded(yielding, DEFAULT_PRIORITY);
1582 queue.push_back(peer, DEFAULT_PRIORITY);
1583 assert_eq!(queue.tentative_pop_next(), Some(peer));
1584 assert_eq!(queue.commit_tentative_pop(), peer);
1585
1586 queue.push_back(peer, DEFAULT_PRIORITY);
1587 assert_eq!(queue.yielded_skip, Some(yielding));
1588 assert_eq!(queue.tentative_pop_next(), Some(peer));
1589 assert_eq!(queue.commit_tentative_pop_completed_turn(), peer);
1590 assert_eq!(queue.yielded_skip, None);
1591 }
1592
1593 fn take_turn(queue: &mut RunQueue) -> DetTid {
1595 queue.tentative_pop_next().expect("a runnable thread");
1596 queue.commit_tentative_pop_completed_turn()
1597 }
1598
1599 fn yield_turn(queue: &mut RunQueue, tid: DetTid, priority: Priority) {
1602 assert_eq!(queue.tentative_pop_tid(tid), Some(tid));
1603 assert_eq!(queue.commit_tentative_pop_yield(), tid);
1604 queue.push_yielded_into_epoch(tid, priority);
1605 }
1606
1607 fn yield_into_epoch(queue: &mut RunQueue, tid: DetTid, priority: Priority) {
1610 for _ in 0..=PLAIN_YIELDS_BEFORE_EPOCH {
1611 yield_turn(queue, tid, priority);
1612 }
1613 assert!(
1614 queue
1615 .yield_epoch
1616 .as_ref()
1617 .is_some_and(|epoch| epoch.contains(&tid))
1618 );
1619 }
1620
1621 #[test]
1625 fn a_yielder_is_reselected_once_before_it_joins_the_epoch() {
1626 let yielder = DetTid::from_raw(1);
1627 let awaited = DetTid::from_raw(2);
1628 let mut queue = RunQueue::default();
1629 queue.push_back(yielder, FIRST_PRIORITY);
1630 queue.push_back(awaited, LAST_PRIORITY);
1631
1632 yield_turn(&mut queue, yielder, FIRST_PRIORITY);
1633 assert_eq!(queue.yield_epoch, None);
1634 assert_eq!(queue.tentative_pop_next(), Some(yielder));
1635 queue.undo_tentative_pop();
1636 yield_turn(&mut queue, yielder, FIRST_PRIORITY);
1637 assert_eq!(take_turn(&mut queue), awaited);
1638 assert!(queue.yield_streaks.is_empty());
1639 }
1640
1641 #[test]
1648 fn consecutive_lone_yields_build_no_streak() {
1649 let spinner = DetTid::from_raw(1);
1650 let woken = DetTid::from_raw(2);
1651 let mut queue = RunQueue::default();
1652 queue.push_back(spinner, FIRST_PRIORITY);
1653 for _ in 0..5 {
1654 yield_turn(&mut queue, spinner, FIRST_PRIORITY);
1655 }
1656 assert!(queue.yield_streaks.is_empty());
1657 assert_eq!(queue.yield_epoch, None);
1658 queue.push_back(woken, LAST_PRIORITY);
1659 yield_turn(&mut queue, spinner, FIRST_PRIORITY);
1660 assert_eq!(queue.yield_epoch, None);
1661 assert_eq!(queue.tentative_pop_next(), Some(spinner));
1662 }
1663
1664 #[test]
1668 fn the_last_thread_outside_an_epoch_joins_it_by_yielding() {
1669 let first = DetTid::from_raw(1);
1670 let last = DetTid::from_raw(2);
1671 let mut queue = RunQueue::default();
1672 queue.push_back(first, FIRST_PRIORITY);
1673 queue.push_back(last, LAST_PRIORITY);
1674
1675 yield_into_epoch(&mut queue, first, FIRST_PRIORITY);
1676 assert_eq!(queue.tentative_pop_next(), Some(last));
1677 queue.undo_tentative_pop();
1678 yield_into_epoch(&mut queue, last, LAST_PRIORITY);
1679 assert_eq!(queue.tentative_pop_next(), Some(first));
1680 assert_eq!(queue.yield_epoch, None);
1681 }
1682
1683 #[test]
1687 fn two_yielders_cannot_shut_out_a_thread_in_a_later_band() {
1688 let first = DetTid::from_raw(1);
1689 let second = DetTid::from_raw(2);
1690 let awaited = DetTid::from_raw(3);
1691 let mut queue = RunQueue::default();
1692 queue.push_back(first, FIRST_PRIORITY);
1693 queue.push_back(second, FIRST_PRIORITY + 1);
1694 queue.push_back(awaited, LAST_PRIORITY);
1695
1696 yield_into_epoch(&mut queue, first, FIRST_PRIORITY);
1697 assert_eq!(queue.tentative_pop_next(), Some(second));
1698 queue.undo_tentative_pop();
1699 yield_into_epoch(&mut queue, second, FIRST_PRIORITY + 1);
1700 assert_eq!(take_turn(&mut queue), awaited);
1701 }
1702
1703 #[test]
1707 fn a_turn_by_a_thread_that_did_not_yield_ends_the_yield_epoch() {
1708 let yielder = DetTid::from_raw(1);
1709 let early = DetTid::from_raw(2);
1710 let late = DetTid::from_raw(3);
1711 let mut queue = RunQueue::default();
1712 queue.push_back(yielder, FIRST_PRIORITY + 1);
1713 queue.push_back(early, FIRST_PRIORITY);
1714 queue.push_back(late, LAST_PRIORITY);
1715
1716 yield_into_epoch(&mut queue, yielder, FIRST_PRIORITY + 1);
1717 assert_eq!(take_turn(&mut queue), early);
1718 assert_eq!(queue.yield_epoch, None);
1719 queue.push_back(early, FIRST_PRIORITY);
1720 assert_eq!(take_turn(&mut queue), early);
1721 queue.push_back(early, FIRST_PRIORITY);
1722 yield_into_epoch(&mut queue, yielder, FIRST_PRIORITY + 1);
1726 queue.tentative_pop_next();
1727 assert_eq!(queue.commit_tentative_pop(), early);
1728 queue.push_back(early, FIRST_PRIORITY);
1729 assert!(
1730 queue
1731 .yield_epoch
1732 .as_ref()
1733 .is_some_and(|epoch| epoch.contains(&yielder))
1734 );
1735 queue.end_yield_epoch();
1736 assert_eq!(queue.yield_epoch, None);
1737 assert!(queue.yield_streaks.is_empty());
1738 assert_eq!(
1739 queue.tids().copied().collect::<Vec<_>>(),
1740 [early, yielder, late]
1741 );
1742 }
1743
1744 #[test]
1747 fn a_yield_epoch_covering_every_queued_thread_ends() {
1748 let first = DetTid::from_raw(1);
1749 let second = DetTid::from_raw(2);
1750 let mut queue = RunQueue::default();
1751 queue.push_back(first, FIRST_PRIORITY);
1752 queue.push_back(second, LAST_PRIORITY);
1753
1754 yield_into_epoch(&mut queue, first, FIRST_PRIORITY);
1755 assert_eq!(queue.tentative_pop_next(), Some(second));
1756 queue.undo_tentative_pop();
1757 yield_into_epoch(&mut queue, second, LAST_PRIORITY);
1758 assert_eq!(queue.tentative_pop_next(), Some(first));
1759 assert_eq!(queue.yield_epoch, None);
1760 queue.undo_tentative_pop();
1761 yield_into_epoch(&mut queue, first, FIRST_PRIORITY);
1762 assert_eq!(queue.tentative_pop_next(), Some(second));
1763 }
1764
1765 #[test]
1768 fn a_yield_epoch_keeps_the_yielders_band_and_poller_status() {
1769 let yielder = DetTid::from_raw(1);
1770 let awaited = DetTid::from_raw(2);
1771 let mut queue = RunQueue::default();
1772 queue.push_back(yielder, FIRST_PRIORITY);
1773 queue.push_back(awaited, LAST_PRIORITY);
1774
1775 yield_into_epoch(&mut queue, yielder, FIRST_PRIORITY);
1776 assert!(!queue.only_pollers());
1777 assert!(queue.has_runnable_besides(awaited));
1778 assert_eq!(
1779 queue.tids().copied().collect::<Vec<_>>(),
1780 [yielder, awaited]
1781 );
1782 assert_eq!(take_turn(&mut queue), awaited);
1783 }
1784
1785 #[test]
1788 fn leaving_the_queue_leaves_the_yield_epoch() {
1789 let yielder = DetTid::from_raw(1);
1790 let other = DetTid::from_raw(2);
1791 let mut queue = RunQueue::default();
1792 queue.push_back(yielder, FIRST_PRIORITY);
1793 queue.push_back(other, LAST_PRIORITY);
1794
1795 yield_into_epoch(&mut queue, yielder, FIRST_PRIORITY);
1796 assert!(queue.remove_tid(yielder));
1797 queue.push_front(yielder, FIRST_PRIORITY);
1798 assert_eq!(take_turn(&mut queue), yielder);
1799 }
1800
1801 #[test]
1806 fn only_a_fully_backed_off_poller_releases_a_yield_epoch() {
1807 let yielder = DetTid::from_raw(1);
1808 let other = DetTid::from_raw(2);
1809 for poller in [false, true] {
1810 let mut queue = RunQueue::default();
1811 queue.push_back(yielder, FIRST_PRIORITY);
1812 if poller {
1813 queue.push_poller(other, DEFAULT_PRIORITY, 20);
1814 } else {
1815 queue.push_back(other, LAST_PRIORITY);
1816 }
1817 yield_into_epoch(&mut queue, yielder, FIRST_PRIORITY);
1818 let expected = if poller { yielder } else { other };
1819 assert_eq!(
1820 queue.tentative_pop_next(),
1821 Some(expected),
1822 "poller={poller}"
1823 );
1824 }
1825 }
1826
1827 #[test]
1830 fn leaving_the_queue_resets_the_yield_streak() {
1831 let yielder = DetTid::from_raw(1);
1832 let other = DetTid::from_raw(2);
1833 let mut queue = RunQueue::default();
1834 queue.push_back(yielder, FIRST_PRIORITY);
1835 queue.push_back(other, LAST_PRIORITY);
1836
1837 yield_turn(&mut queue, yielder, FIRST_PRIORITY);
1838 assert!(queue.remove_tid(yielder));
1839 queue.push_front(yielder, FIRST_PRIORITY);
1840 yield_turn(&mut queue, yielder, FIRST_PRIORITY);
1841 assert_eq!(queue.yield_epoch, None);
1842 assert_eq!(queue.tentative_pop_next(), Some(yielder));
1843 }
1844
1845 #[test]
1848 fn a_one_turn_skip_and_a_yield_epoch_never_exclude_everyone() {
1849 let yielder = DetTid::from_raw(1);
1850 let poller = DetTid::from_raw(2);
1851 let mut queue = RunQueue::default();
1852 queue.push_back(yielder, FIRST_PRIORITY);
1853 queue.push_back(poller, DEFAULT_PRIORITY);
1854
1855 yield_into_epoch(&mut queue, yielder, FIRST_PRIORITY);
1856 assert_eq!(queue.tentative_pop_tid(poller), Some(poller));
1857 assert_eq!(queue.commit_tentative_pop_yield(), poller);
1858 queue.push_yielded(poller, DEFAULT_PRIORITY);
1859 assert_eq!(queue.tentative_pop_next(), Some(yielder));
1862 }
1863
1864 #[test]
1866 fn a_lone_yielder_runs_again() {
1867 let yielder = DetTid::from_raw(1);
1868 let mut queue = RunQueue::default();
1869 queue.push_back(yielder, DEFAULT_PRIORITY);
1870
1871 yield_turn(&mut queue, yielder, DEFAULT_PRIORITY);
1872 assert_eq!(take_turn(&mut queue), yielder);
1873 assert_eq!(queue.yield_epoch, None);
1874 assert!(queue.yield_streaks.is_empty());
1875 }
1876
1877 #[test]
1880 fn a_yield_epoch_holds_under_the_random_heuristics() {
1881 for strategy in [SchedHeuristic::Random, SchedHeuristic::StickyRandom] {
1882 for seed in 0..16 {
1883 let yielders = [DetTid::from_raw(1), DetTid::from_raw(2)];
1884 let awaited = DetTid::from_raw(3);
1885 let mut queue = RunQueue::new(strategy, seed, 1.0);
1886 for tid in [yielders[0], yielders[1], awaited] {
1887 queue.push_back(tid, DEFAULT_PRIORITY);
1888 }
1889 for tid in yielders {
1890 yield_into_epoch(&mut queue, tid, DEFAULT_PRIORITY);
1891 }
1892 assert_eq!(take_turn(&mut queue), awaited, "{strategy:?} seed {seed}");
1893 }
1894 }
1895 }
1896
1897 #[test]
1898 fn threads_queued_by_a_yield_are_not_work_a_background_call_waits_behind() {
1899 let first = DetTid::from_raw(1);
1900 let second = DetTid::from_raw(2);
1901 let worker = DetTid::from_raw(3);
1902 let mut queue = RunQueue::default();
1903
1904 queue.push_back(first, DEFAULT_PRIORITY);
1905 queue.push_back(second, DEFAULT_PRIORITY);
1906 assert!(!queue.only_pollers_or_yielders());
1907
1908 assert_eq!(queue.tentative_pop_next(), Some(first));
1911 assert_eq!(queue.commit_tentative_pop_completed_turn(), first);
1912 queue.push_yielded(first, DEFAULT_PRIORITY);
1913 assert!(
1914 !queue.only_pollers_or_yielders(),
1915 "second has not yielded yet"
1916 );
1917 assert_eq!(queue.tentative_pop_next(), Some(second));
1918 assert_eq!(queue.commit_tentative_pop_completed_turn(), second);
1919 queue.push_yielded(second, DEFAULT_PRIORITY);
1920 assert_eq!(queue.yielded_skip, Some(second));
1921 assert!(!queue.only_pollers());
1922 assert!(queue.only_pollers_or_yielders());
1923
1924 queue.push_back(worker, DEFAULT_PRIORITY);
1926 assert!(!queue.only_pollers_or_yielders());
1927 assert!(queue.remove_tid(worker));
1928 assert!(queue.only_pollers_or_yielders());
1929
1930 assert_eq!(queue.tentative_pop_next(), Some(first));
1932 assert_eq!(queue.commit_tentative_pop_completed_turn(), first);
1933 queue.push_back(first, DEFAULT_PRIORITY);
1934 assert!(!queue.only_pollers_or_yielders());
1935 }
1936
1937 #[test]
1938 fn tentative_pop_in_progress_tracks_the_transaction() {
1939 let a = DetTid::from_raw(1);
1940 let b = DetTid::from_raw(2);
1941 let mut queue = RunQueue::default();
1942
1943 assert!(!queue.tentative_pop_in_progress());
1945 queue.push_back(a, DEFAULT_PRIORITY);
1946 queue.push_back(b, DEFAULT_PRIORITY);
1947 assert!(!queue.tentative_pop_in_progress());
1948
1949 assert_eq!(queue.tentative_pop_next(), Some(a));
1953 assert!(queue.tentative_pop_in_progress());
1954
1955 assert_eq!(queue.commit_tentative_pop(), a);
1957 assert!(!queue.tentative_pop_in_progress());
1958
1959 assert_eq!(queue.tentative_pop_tid(b), Some(b));
1961 assert!(queue.tentative_pop_in_progress());
1962 queue.undo_tentative_pop();
1963 assert!(!queue.tentative_pop_in_progress());
1964 }
1965
1966 #[test]
1967 fn removal_clears_per_incarnation_selection_state_before_tid_reuse() {
1968 let tid = DetTid::from_raw(7);
1969 let mut queue = RunQueue::new(SchedHeuristic::StickyRandom, 0x5107, 1.0);
1970 queue.push_back(tid, DEFAULT_PRIORITY);
1971
1972 assert_eq!(queue.tentative_pop_next(), Some(tid));
1973 queue.undo_tentative_pop();
1974 assert_eq!(queue.sticky_random_selection, Some(tid));
1975 queue.yielded_skip = Some(tid);
1978
1979 assert!(queue.remove_tid(tid));
1980 assert_eq!(queue.sticky_random_selection, None);
1981 assert_eq!(queue.yielded_skip, None);
1982
1983 queue.push_back(tid, DEFAULT_PRIORITY);
1984 assert_eq!(queue.sticky_random_selection, None);
1985 assert_eq!(queue.yielded_skip, None);
1986 }
1987}