1use crate::task::{RoleOverrides, Task};
6use fidl::HandleBased;
7use fidl_fuchsia_scheduler::{
8 RoleManagerMarker, RoleManagerSetRoleRequest, RoleManagerSynchronousProxy, RoleName, RoleTarget,
9};
10use fuchsia_component::client::connect_to_protocol_sync;
11use starnix_logging::{impossible_error, log_debug, log_warn, track_stub};
12use starnix_uapi::errors::Errno;
13use starnix_uapi::{
14 SCHED_BATCH, SCHED_DEADLINE, SCHED_FIFO, SCHED_IDLE, SCHED_NORMAL, SCHED_RESET_ON_FORK,
15 SCHED_RR, errno, error, sched_param,
16};
17
18pub struct SchedulerManager {
19 role_manager: Option<RoleManagerSynchronousProxy>,
20 role_overrides: RoleOverrides,
21}
22
23impl SchedulerManager {
24 pub fn new(role_overrides: RoleOverrides) -> SchedulerManager {
27 let role_manager = fuchsia_runtime::with_thread_self(|thread| {
28 let role_manager = connect_to_protocol_sync::<RoleManagerMarker>().unwrap();
29 if let Err(e) = Self::set_thread_role_inner(
30 &role_manager,
31 thread,
32 SchedulerState::default().role_name(),
33 ) {
34 log_debug!("Setting thread role failed ({e:?}), will not set thread priority.");
35 None
36 } else {
37 log_debug!("Thread role set successfully, scheduler manager initialized.");
38 Some(role_manager)
39 }
40 });
41
42 SchedulerManager { role_manager, role_overrides }
43 }
44
45 pub fn empty_for_tests() -> Self {
47 Self { role_manager: None, role_overrides: RoleOverrides::new().build().unwrap() }
48 }
49
50 pub fn role_name(&self, task: &Task) -> Result<&str, Errno> {
53 let scheduler_state = task.read().scheduler_state;
54 self.role_name_inner(task, scheduler_state)
55 }
56
57 fn role_name_inner(&self, task: &Task, scheduler_state: SchedulerState) -> Result<&str, Errno> {
58 Ok(if scheduler_state.is_realtime() {
59 let process_name = task
60 .thread_group()
61 .read()
62 .get_task(task.thread_group().leader)
63 .ok_or_else(|| errno!(EINVAL))?
64 .command();
65 let thread_name = task.command();
66 if let Some(name) = self.role_overrides.get_role_name(&process_name, &thread_name) {
67 name
68 } else {
69 scheduler_state.role_name()
70 }
71 } else {
72 scheduler_state.role_name()
73 })
74 }
75
76 pub fn set_thread_role(
81 &self,
82 task: &Task,
83 scheduler_state: SchedulerState,
84 ) -> Result<(), Errno> {
85 let Some(role_manager) = self.role_manager.as_ref() else {
86 log_debug!("no role manager for setting role");
87 return Ok(());
88 };
89
90 let role_name = self.role_name_inner(task, scheduler_state)?;
91 let thread = task.thread.read();
92 let Some(thread) = thread.as_ref() else {
93 log_debug!("thread role update requested for task without thread, skipping");
94 return Ok(());
95 };
96 Self::set_thread_role_inner(role_manager, thread, role_name)
97 }
98
99 fn set_thread_role_inner(
100 role_manager: &RoleManagerSynchronousProxy,
101 thread: &zx::Thread,
102 role_name: &str,
103 ) -> Result<(), Errno> {
104 log_debug!(role_name; "setting thread role");
105
106 let thread = thread.duplicate_handle(zx::Rights::SAME_RIGHTS).map_err(impossible_error)?;
107 let request = RoleManagerSetRoleRequest {
108 target: Some(RoleTarget::Thread(thread)),
109 role: Some(RoleName { role: role_name.to_string() }),
110 ..Default::default()
111 };
112 let _ = role_manager.set_role(request, zx::MonotonicInstant::INFINITE).map_err(|err| {
113 log_warn!(err:%; "Unable to set thread role.");
114 errno!(EINVAL)
115 })?;
116 Ok(())
117 }
118}
119
120#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
125pub struct NormalPriority {
126 value: u8,
129}
130
131impl NormalPriority {
132 const MIN_VALUE: u8 = 1;
133 const DEFAULT_VALUE: u8 = 20;
134 const MAX_VALUE: u8 = 40;
135
136 pub(crate) fn from_setpriority_syscall(user_nice: i32) -> Self {
143 Self {
144 value: (Self::DEFAULT_VALUE as i32)
145 .saturating_sub(user_nice)
146 .clamp(Self::MIN_VALUE as i32, Self::MAX_VALUE as i32) as u8,
147 }
148 }
149
150 pub fn from_binder(user_nice: i8) -> Result<Self, Errno> {
157 let value = (Self::DEFAULT_VALUE as i8).saturating_sub(user_nice);
158 if value < (Self::MIN_VALUE as i8) || value > (Self::MAX_VALUE as i8) {
159 return error!(EINVAL);
160 }
161 Ok(Self { value: u8::try_from(value).expect("normal priority should fit in a u8") })
162 }
163
164 pub fn as_nice(&self) -> i8 {
167 (Self::DEFAULT_VALUE as i8) - (self.value as i8)
168 }
169
170 pub(crate) fn raw_priority(&self) -> u8 {
173 self.value
174 }
175
176 pub(crate) fn exceeds(&self, limit: u64) -> bool {
178 limit < (self.value as u64)
179 }
180}
181
182impl std::default::Default for NormalPriority {
183 fn default() -> Self {
184 Self { value: Self::DEFAULT_VALUE }
185 }
186}
187
188#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
192pub(crate) struct RealtimePriority {
193 value: u8,
197}
198
199impl RealtimePriority {
200 const NON_REAL_TIME_VALUE: u8 = 0;
201 const MIN_VALUE: u8 = 1;
202 const MAX_VALUE: u8 = 99;
203
204 const NON_REAL_TIME: RealtimePriority = RealtimePriority { value: Self::NON_REAL_TIME_VALUE };
205
206 pub(crate) fn exceeds(&self, limit: u64) -> bool {
207 limit < (self.value as u64)
208 }
209}
210
211#[derive(Clone, Copy, Debug, Eq, PartialEq)]
213pub(crate) enum SchedulingPolicy {
214 Normal,
215 Batch,
216 Idle,
217 Fifo,
218 RoundRobin,
219}
220
221impl SchedulingPolicy {
222 fn realtime_priority_min(&self) -> u8 {
223 match self {
224 Self::Normal | Self::Batch | Self::Idle => RealtimePriority::NON_REAL_TIME_VALUE,
225 Self::Fifo | Self::RoundRobin => RealtimePriority::MIN_VALUE,
226 }
227 }
228
229 fn realtime_priority_max(&self) -> u8 {
230 match self {
231 Self::Normal | Self::Batch | Self::Idle => RealtimePriority::NON_REAL_TIME_VALUE,
232 Self::Fifo | Self::RoundRobin => RealtimePriority::MAX_VALUE,
233 }
234 }
235
236 pub(crate) fn realtime_priority_from(&self, priority: i32) -> Result<RealtimePriority, Errno> {
237 let priority = u8::try_from(priority).map_err(|_| errno!(EINVAL))?;
238 if priority < self.realtime_priority_min() || priority > self.realtime_priority_max() {
239 return error!(EINVAL);
240 }
241 Ok(RealtimePriority { value: priority })
242 }
243}
244
245impl TryFrom<u32> for SchedulingPolicy {
246 type Error = Errno;
247
248 fn try_from(value: u32) -> Result<Self, Errno> {
249 Ok(match value {
250 SCHED_NORMAL => Self::Normal,
251 SCHED_BATCH => Self::Batch,
252 SCHED_IDLE => Self::Idle,
253 SCHED_FIFO => Self::Fifo,
254 SCHED_RR => Self::RoundRobin,
255 _ => {
256 return error!(EINVAL);
257 }
258 })
259 }
260}
261
262#[derive(Clone, Copy, Debug, Eq, PartialEq)]
263pub struct SchedulerState {
264 pub(crate) policy: SchedulingPolicy,
265 pub(crate) normal_priority: NormalPriority,
269 pub(crate) realtime_priority: RealtimePriority,
272 pub(crate) reset_on_fork: bool,
273}
274
275impl SchedulerState {
276 pub fn is_default(&self) -> bool {
277 self == &Self::default()
278 }
279
280 pub fn from_binder(policy: u8, priority_or_nice: u8) -> Result<Self, Errno> {
286 let (policy, normal_priority, realtime_priority) = match policy as u32 {
287 SCHED_NORMAL => (
288 SchedulingPolicy::Normal,
289 NormalPriority::from_binder(priority_or_nice as i8)?,
290 RealtimePriority::NON_REAL_TIME,
291 ),
292 SCHED_BATCH => (
293 SchedulingPolicy::Batch,
294 NormalPriority::from_binder(priority_or_nice as i8)?,
295 RealtimePriority::NON_REAL_TIME,
296 ),
297 SCHED_FIFO => (
298 SchedulingPolicy::Fifo,
299 NormalPriority::default(),
300 SchedulingPolicy::Fifo.realtime_priority_from(priority_or_nice as i32)?,
301 ),
302 SCHED_RR => (
303 SchedulingPolicy::RoundRobin,
304 NormalPriority::default(),
305 SchedulingPolicy::RoundRobin.realtime_priority_from(priority_or_nice as i32)?,
306 ),
307 _ => return error!(EINVAL),
308 };
309 Ok(Self { policy, normal_priority, realtime_priority, reset_on_fork: false })
310 }
311
312 pub fn fork(self) -> Self {
313 if self.reset_on_fork {
314 let (policy, normal_priority, realtime_priority) = if self.is_realtime() {
315 (
321 SchedulingPolicy::Normal,
322 NormalPriority::default(),
323 RealtimePriority::NON_REAL_TIME,
324 )
325 } else {
326 (
331 self.policy,
332 std::cmp::min(self.normal_priority, NormalPriority::default()),
333 RealtimePriority::NON_REAL_TIME,
334 )
335 };
336 Self {
337 policy,
338 normal_priority,
339 realtime_priority,
340 reset_on_fork: false,
342 }
343 } else {
344 self
345 }
346 }
347
348 pub fn policy_for_sched_getscheduler(&self) -> u32 {
354 let mut base = match self.policy {
355 SchedulingPolicy::Normal => SCHED_NORMAL,
356 SchedulingPolicy::Batch => SCHED_BATCH,
357 SchedulingPolicy::Idle => SCHED_IDLE,
358 SchedulingPolicy::Fifo => SCHED_FIFO,
359 SchedulingPolicy::RoundRobin => SCHED_RR,
360 };
361 if self.reset_on_fork {
362 base |= SCHED_RESET_ON_FORK;
363 }
364 base
365 }
366
367 pub fn get_sched_param(&self) -> sched_param {
372 sched_param {
373 sched_priority: (if self.is_realtime() {
374 self.realtime_priority.value
375 } else {
376 RealtimePriority::NON_REAL_TIME_VALUE
377 }) as i32,
378 }
379 }
380
381 pub fn normal_priority(&self) -> NormalPriority {
382 self.normal_priority
383 }
384
385 pub fn is_realtime(&self) -> bool {
386 match self.policy {
387 SchedulingPolicy::Normal | SchedulingPolicy::Batch | SchedulingPolicy::Idle => false,
388 SchedulingPolicy::Fifo | SchedulingPolicy::RoundRobin => true,
389 }
390 }
391
392 fn role_name(&self) -> &'static str {
405 match self.policy {
406 SchedulingPolicy::Idle => FAIR_PRIORITY_ROLE_NAMES[0],
409
410 SchedulingPolicy::Normal => {
413 FAIR_PRIORITY_ROLE_NAMES[(self.normal_priority.value as usize / 2) + 6]
414 }
415 SchedulingPolicy::Batch => {
416 track_stub!(TODO("https://fxbug.dev/308055542"), "SCHED_BATCH hinting");
417 FAIR_PRIORITY_ROLE_NAMES[(self.normal_priority.value as usize / 2) + 6]
418 }
419
420 SchedulingPolicy::Fifo | SchedulingPolicy::RoundRobin => REALTIME_ROLE_NAME,
426 }
427 }
428
429 pub fn is_less_than_for_binder(&self, other: Self) -> bool {
432 match self.policy {
433 SchedulingPolicy::Fifo | SchedulingPolicy::RoundRobin => match other.policy {
434 SchedulingPolicy::Fifo | SchedulingPolicy::RoundRobin => {
435 self.realtime_priority < other.realtime_priority
436 }
437 SchedulingPolicy::Normal | SchedulingPolicy::Batch | SchedulingPolicy::Idle => {
438 false
439 }
440 },
441 SchedulingPolicy::Normal => match other.policy {
442 SchedulingPolicy::Fifo | SchedulingPolicy::RoundRobin => true,
443 SchedulingPolicy::Normal => {
444 self.normal_priority.value < other.normal_priority.value
445 }
446 SchedulingPolicy::Batch | SchedulingPolicy::Idle => false,
447 },
448 SchedulingPolicy::Batch => match other.policy {
449 SchedulingPolicy::Fifo
450 | SchedulingPolicy::RoundRobin
451 | SchedulingPolicy::Normal => true,
452 SchedulingPolicy::Batch => self.normal_priority.value < other.normal_priority.value,
453 SchedulingPolicy::Idle => false,
454 },
455 SchedulingPolicy::Idle => match other.policy {
457 SchedulingPolicy::Fifo
458 | SchedulingPolicy::RoundRobin
459 | SchedulingPolicy::Normal
460 | SchedulingPolicy::Batch => true,
461 SchedulingPolicy::Idle => false,
462 },
463 }
464 }
465}
466
467impl std::default::Default for SchedulerState {
468 fn default() -> Self {
469 Self {
470 policy: SchedulingPolicy::Normal,
471 normal_priority: NormalPriority::default(),
472 realtime_priority: RealtimePriority::NON_REAL_TIME,
473 reset_on_fork: false,
474 }
475 }
476}
477
478pub fn min_priority_for_sched_policy(policy: u32) -> Result<u8, Errno> {
479 Ok(match policy {
480 SCHED_DEADLINE => RealtimePriority::NON_REAL_TIME_VALUE,
481 _ => SchedulingPolicy::try_from(policy)?.realtime_priority_min(),
482 })
483}
484
485pub fn max_priority_for_sched_policy(policy: u32) -> Result<u8, Errno> {
486 Ok(match policy {
487 SCHED_DEADLINE => RealtimePriority::NON_REAL_TIME_VALUE,
488 _ => SchedulingPolicy::try_from(policy)?.realtime_priority_max(),
489 })
490}
491
492const FAIR_PRIORITY_ROLE_NAMES: [&str; 32] = [
496 "fuchsia.starnix.fair.0",
497 "fuchsia.starnix.fair.1",
498 "fuchsia.starnix.fair.2",
499 "fuchsia.starnix.fair.3",
500 "fuchsia.starnix.fair.4",
501 "fuchsia.starnix.fair.5",
502 "fuchsia.starnix.fair.6",
503 "fuchsia.starnix.fair.7",
504 "fuchsia.starnix.fair.8",
505 "fuchsia.starnix.fair.9",
506 "fuchsia.starnix.fair.10",
507 "fuchsia.starnix.fair.11",
508 "fuchsia.starnix.fair.12",
509 "fuchsia.starnix.fair.13",
510 "fuchsia.starnix.fair.14",
511 "fuchsia.starnix.fair.15",
512 "fuchsia.starnix.fair.16",
513 "fuchsia.starnix.fair.17",
514 "fuchsia.starnix.fair.18",
515 "fuchsia.starnix.fair.19",
516 "fuchsia.starnix.fair.20",
517 "fuchsia.starnix.fair.21",
518 "fuchsia.starnix.fair.22",
519 "fuchsia.starnix.fair.23",
520 "fuchsia.starnix.fair.24",
521 "fuchsia.starnix.fair.25",
522 "fuchsia.starnix.fair.26",
523 "fuchsia.starnix.fair.27",
524 "fuchsia.starnix.fair.28",
525 "fuchsia.starnix.fair.29",
526 "fuchsia.starnix.fair.30",
527 "fuchsia.starnix.fair.31",
528];
529const REALTIME_ROLE_NAME: &str = "fuchsia.starnix.realtime";
530#[cfg(test)]
533mod tests {
534 use super::*;
535 use assert_matches::assert_matches;
536
537 #[fuchsia::test]
538 fn default_role_name() {
539 assert_eq!(SchedulerState::default().role_name(), "fuchsia.starnix.fair.16");
540 }
541
542 #[fuchsia::test]
543 fn normal_with_non_default_nice_role_name() {
544 assert_eq!(
545 SchedulerState {
546 policy: SchedulingPolicy::Normal,
547 normal_priority: NormalPriority { value: 10 },
548 realtime_priority: RealtimePriority::NON_REAL_TIME,
549 reset_on_fork: false
550 }
551 .role_name(),
552 "fuchsia.starnix.fair.11"
553 );
554 assert_eq!(
555 SchedulerState {
556 policy: SchedulingPolicy::Normal,
557 normal_priority: NormalPriority { value: 27 },
558 realtime_priority: RealtimePriority::NON_REAL_TIME,
559 reset_on_fork: false
560 }
561 .role_name(),
562 "fuchsia.starnix.fair.19"
563 );
564 }
565
566 #[fuchsia::test]
567 fn fifo_role_name() {
568 assert_eq!(
569 SchedulerState {
570 policy: SchedulingPolicy::Fifo,
571 normal_priority: NormalPriority::default(),
572 realtime_priority: RealtimePriority { value: 1 },
573 reset_on_fork: false
574 }
575 .role_name(),
576 "fuchsia.starnix.realtime",
577 );
578 assert_eq!(
579 SchedulerState {
580 policy: SchedulingPolicy::Fifo,
581 normal_priority: NormalPriority::default(),
582 realtime_priority: RealtimePriority { value: 2 },
583 reset_on_fork: false
584 }
585 .role_name(),
586 "fuchsia.starnix.realtime",
587 );
588 assert_eq!(
589 SchedulerState {
590 policy: SchedulingPolicy::Fifo,
591 normal_priority: NormalPriority::default(),
592 realtime_priority: RealtimePriority { value: 99 },
593 reset_on_fork: false
594 }
595 .role_name(),
596 "fuchsia.starnix.realtime",
597 );
598 }
599
600 #[fuchsia::test]
601 fn idle_role_name() {
602 assert_eq!(
603 SchedulerState {
604 policy: SchedulingPolicy::Idle,
605 normal_priority: NormalPriority { value: 1 },
606 realtime_priority: RealtimePriority::NON_REAL_TIME,
607 reset_on_fork: false,
608 }
609 .role_name(),
610 "fuchsia.starnix.fair.0"
611 );
612 assert_eq!(
613 SchedulerState {
614 policy: SchedulingPolicy::Idle,
615 normal_priority: NormalPriority::default(),
616 realtime_priority: RealtimePriority::NON_REAL_TIME,
617 reset_on_fork: false,
618 }
619 .role_name(),
620 "fuchsia.starnix.fair.0"
621 );
622 assert_eq!(
623 SchedulerState {
624 policy: SchedulingPolicy::Idle,
625 normal_priority: NormalPriority { value: 40 },
626 realtime_priority: RealtimePriority::NON_REAL_TIME,
627 reset_on_fork: false,
628 }
629 .role_name(),
630 "fuchsia.starnix.fair.0"
631 );
632 }
633
634 #[fuchsia::test]
635 fn build_policy_from_binder() {
636 assert_matches!(SchedulerState::from_binder(SCHED_NORMAL as u8, 0), Ok(_));
637 assert_matches!(
638 SchedulerState::from_binder(SCHED_NORMAL as u8, ((-21) as i8) as u8),
639 Err(_)
640 );
641 assert_matches!(
642 SchedulerState::from_binder(SCHED_NORMAL as u8, ((-20) as i8) as u8),
643 Ok(SchedulerState {
644 policy: SchedulingPolicy::Normal,
645 normal_priority: NormalPriority { value: 40 },
646 realtime_priority: RealtimePriority::NON_REAL_TIME,
647 reset_on_fork: false,
648 })
649 );
650 assert_matches!(SchedulerState::from_binder(SCHED_NORMAL as u8, 1), Ok(_));
651 assert_matches!(SchedulerState::from_binder(SCHED_NORMAL as u8, 19), Ok(_));
652 assert_matches!(SchedulerState::from_binder(SCHED_NORMAL as u8, 20), Err(_));
653 assert_matches!(SchedulerState::from_binder(SCHED_FIFO as u8, 0), Err(_));
654 assert_matches!(SchedulerState::from_binder(SCHED_FIFO as u8, 1), Ok(_));
655 assert_matches!(SchedulerState::from_binder(SCHED_FIFO as u8, 99), Ok(_));
656 assert_matches!(SchedulerState::from_binder(SCHED_FIFO as u8, 100), Err(_));
657 assert_matches!(SchedulerState::from_binder(SCHED_RR as u8, 0), Err(_));
658 assert_matches!(SchedulerState::from_binder(SCHED_RR as u8, 1), Ok(_));
659 assert_matches!(SchedulerState::from_binder(SCHED_RR as u8, 99), Ok(_));
660 assert_matches!(SchedulerState::from_binder(SCHED_RR as u8, 100), Err(_));
661 assert_matches!(SchedulerState::from_binder(SCHED_BATCH as u8, 11), Ok(_));
662 assert_eq!(SchedulerState::from_binder(SCHED_IDLE as u8, 11), error!(EINVAL));
663 assert_matches!(SchedulerState::from_binder(42, 0), Err(_));
664 assert_matches!(SchedulerState::from_binder(42, 0), Err(_));
665 }
666
667 #[fuchsia::test]
670 fn is_less_than_for_binder() {
671 let rr_50 = SchedulerState {
672 policy: SchedulingPolicy::RoundRobin,
673 normal_priority: NormalPriority { value: 1 },
674 realtime_priority: RealtimePriority { value: 50 },
675 reset_on_fork: false,
676 };
677 let rr_40 = SchedulerState {
678 policy: SchedulingPolicy::RoundRobin,
679 normal_priority: NormalPriority { value: 1 },
680 realtime_priority: RealtimePriority { value: 40 },
681 reset_on_fork: false,
682 };
683 let fifo_50 = SchedulerState {
684 policy: SchedulingPolicy::Fifo,
685 normal_priority: NormalPriority { value: 1 },
686 realtime_priority: RealtimePriority { value: 50 },
687 reset_on_fork: false,
688 };
689 let fifo_40 = SchedulerState {
690 policy: SchedulingPolicy::Fifo,
691 normal_priority: NormalPriority { value: 1 },
692 realtime_priority: RealtimePriority { value: 40 },
693 reset_on_fork: false,
694 };
695 let normal_40 = SchedulerState {
696 policy: SchedulingPolicy::Normal,
697 normal_priority: NormalPriority { value: 40 },
698 realtime_priority: RealtimePriority::NON_REAL_TIME,
699 reset_on_fork: true,
700 };
701 let normal_10 = SchedulerState {
702 policy: SchedulingPolicy::Normal,
703 normal_priority: NormalPriority { value: 10 },
704 realtime_priority: RealtimePriority::NON_REAL_TIME,
705 reset_on_fork: true,
706 };
707 let batch_40 = SchedulerState {
708 policy: SchedulingPolicy::Batch,
709 normal_priority: NormalPriority { value: 40 },
710 realtime_priority: RealtimePriority::NON_REAL_TIME,
711 reset_on_fork: true,
712 };
713 let batch_30 = SchedulerState {
714 policy: SchedulingPolicy::Batch,
715 normal_priority: NormalPriority { value: 30 },
716 realtime_priority: RealtimePriority::NON_REAL_TIME,
717 reset_on_fork: true,
718 };
719 let idle_40 = SchedulerState {
720 policy: SchedulingPolicy::Idle,
721 normal_priority: NormalPriority { value: 40 },
722 realtime_priority: RealtimePriority::NON_REAL_TIME,
723 reset_on_fork: true,
724 };
725 let idle_30 = SchedulerState {
726 policy: SchedulingPolicy::Idle,
727 normal_priority: NormalPriority { value: 30 },
728 realtime_priority: RealtimePriority::NON_REAL_TIME,
729 reset_on_fork: true,
730 };
731 assert!(!fifo_50.is_less_than_for_binder(fifo_50));
732 assert!(!rr_50.is_less_than_for_binder(rr_50));
733 assert!(!fifo_50.is_less_than_for_binder(rr_50));
734 assert!(!rr_50.is_less_than_for_binder(fifo_50));
735 assert!(!fifo_50.is_less_than_for_binder(rr_40));
736 assert!(rr_40.is_less_than_for_binder(fifo_50));
737 assert!(!rr_50.is_less_than_for_binder(fifo_40));
738 assert!(fifo_40.is_less_than_for_binder(rr_50));
739 assert!(!fifo_40.is_less_than_for_binder(normal_40));
740 assert!(normal_40.is_less_than_for_binder(fifo_40));
741 assert!(!rr_40.is_less_than_for_binder(normal_40));
742 assert!(normal_40.is_less_than_for_binder(rr_40));
743 assert!(!normal_40.is_less_than_for_binder(normal_40));
744 assert!(!normal_40.is_less_than_for_binder(normal_10));
745 assert!(normal_10.is_less_than_for_binder(normal_40));
746 assert!(!normal_10.is_less_than_for_binder(batch_40));
747 assert!(batch_40.is_less_than_for_binder(normal_10));
748 assert!(!batch_40.is_less_than_for_binder(batch_40));
749 assert!(!batch_40.is_less_than_for_binder(batch_30));
750 assert!(batch_30.is_less_than_for_binder(batch_40));
751 assert!(!batch_30.is_less_than_for_binder(idle_40));
752 assert!(idle_40.is_less_than_for_binder(batch_30));
753 assert!(!idle_40.is_less_than_for_binder(idle_40));
754 assert!(!idle_40.is_less_than_for_binder(idle_30));
755 assert!(!idle_30.is_less_than_for_binder(idle_40));
756 }
757}