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 let process_name = task
59 .thread_group()
60 .read()
61 .get_task(task.thread_group().leader)
62 .ok_or_else(|| errno!(EINVAL))?
63 .command();
64 let thread_name = task.command();
65 if let Some(name) = self.role_overrides.get_role_name(&process_name, &thread_name) {
66 return Ok(name);
67 }
68 Ok(scheduler_state.role_name())
69 }
70
71 pub fn set_thread_role(
76 &self,
77 task: &Task,
78 scheduler_state: SchedulerState,
79 ) -> Result<(), Errno> {
80 let Some(role_manager) = self.role_manager.as_ref() else {
81 log_debug!("no role manager for setting role");
82 return Ok(());
83 };
84
85 let role_name = self.role_name_inner(task, scheduler_state)?;
86 let thread = task.thread.read();
87 let Some(thread) = thread.as_ref() else {
88 log_debug!("thread role update requested for task without thread, skipping");
89 return Ok(());
90 };
91 Self::set_thread_role_inner(role_manager, thread, role_name)
92 }
93
94 fn set_thread_role_inner(
95 role_manager: &RoleManagerSynchronousProxy,
96 thread: &zx::Thread,
97 role_name: &str,
98 ) -> Result<(), Errno> {
99 log_debug!(role_name; "setting thread role");
100
101 let thread = thread.duplicate_handle(zx::Rights::SAME_RIGHTS).map_err(impossible_error)?;
102 let request = RoleManagerSetRoleRequest {
103 target: Some(RoleTarget::Thread(thread)),
104 role: Some(RoleName { role: role_name.to_string() }),
105 ..Default::default()
106 };
107 let _ = role_manager.set_role(request, zx::MonotonicInstant::INFINITE).map_err(|err| {
108 log_warn!(err:%; "Unable to set thread role.");
109 errno!(EINVAL)
110 })?;
111 Ok(())
112 }
113}
114
115#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
120pub struct NormalPriority {
121 value: u8,
124}
125
126impl NormalPriority {
127 const MIN_VALUE: u8 = 1;
128 const DEFAULT_VALUE: u8 = 20;
129 const MAX_VALUE: u8 = 40;
130
131 pub(crate) fn from_setpriority_syscall(user_nice: i32) -> Self {
138 Self {
139 value: (Self::DEFAULT_VALUE as i32)
140 .saturating_sub(user_nice)
141 .clamp(Self::MIN_VALUE as i32, Self::MAX_VALUE as i32) as u8,
142 }
143 }
144
145 pub fn from_binder(user_nice: i8) -> Result<Self, Errno> {
152 let value = (Self::DEFAULT_VALUE as i8).saturating_sub(user_nice);
153 if value < (Self::MIN_VALUE as i8) || value > (Self::MAX_VALUE as i8) {
154 return error!(EINVAL);
155 }
156 Ok(Self { value: u8::try_from(value).expect("normal priority should fit in a u8") })
157 }
158
159 pub fn as_nice(&self) -> i8 {
162 (Self::DEFAULT_VALUE as i8) - (self.value as i8)
163 }
164
165 pub(crate) fn raw_priority(&self) -> u8 {
168 self.value
169 }
170
171 pub(crate) fn exceeds(&self, limit: u64) -> bool {
173 limit < (self.value as u64)
174 }
175}
176
177impl std::default::Default for NormalPriority {
178 fn default() -> Self {
179 Self { value: Self::DEFAULT_VALUE }
180 }
181}
182
183#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
187pub(crate) struct RealtimePriority {
188 value: u8,
192}
193
194impl RealtimePriority {
195 const NON_REAL_TIME_VALUE: u8 = 0;
196 const MIN_VALUE: u8 = 1;
197 const MAX_VALUE: u8 = 99;
198
199 const NON_REAL_TIME: RealtimePriority = RealtimePriority { value: Self::NON_REAL_TIME_VALUE };
200
201 pub(crate) fn exceeds(&self, limit: u64) -> bool {
202 limit < (self.value as u64)
203 }
204}
205
206#[derive(Clone, Copy, Debug, Eq, PartialEq)]
208pub(crate) enum SchedulingPolicy {
209 Normal,
210 Batch,
211 Idle,
212 Fifo,
213 RoundRobin,
214}
215
216impl SchedulingPolicy {
217 fn realtime_priority_min(&self) -> u8 {
218 match self {
219 Self::Normal | Self::Batch | Self::Idle => RealtimePriority::NON_REAL_TIME_VALUE,
220 Self::Fifo | Self::RoundRobin => RealtimePriority::MIN_VALUE,
221 }
222 }
223
224 fn realtime_priority_max(&self) -> u8 {
225 match self {
226 Self::Normal | Self::Batch | Self::Idle => RealtimePriority::NON_REAL_TIME_VALUE,
227 Self::Fifo | Self::RoundRobin => RealtimePriority::MAX_VALUE,
228 }
229 }
230
231 pub(crate) fn realtime_priority_from(&self, priority: i32) -> Result<RealtimePriority, Errno> {
232 let priority = u8::try_from(priority).map_err(|_| errno!(EINVAL))?;
233 if priority < self.realtime_priority_min() || priority > self.realtime_priority_max() {
234 return error!(EINVAL);
235 }
236 Ok(RealtimePriority { value: priority })
237 }
238}
239
240impl TryFrom<u32> for SchedulingPolicy {
241 type Error = Errno;
242
243 fn try_from(value: u32) -> Result<Self, Errno> {
244 Ok(match value {
245 SCHED_NORMAL => Self::Normal,
246 SCHED_BATCH => Self::Batch,
247 SCHED_IDLE => Self::Idle,
248 SCHED_FIFO => Self::Fifo,
249 SCHED_RR => Self::RoundRobin,
250 _ => {
251 return error!(EINVAL);
252 }
253 })
254 }
255}
256
257#[derive(Clone, Copy, Debug, Eq, PartialEq)]
258pub struct SchedulerState {
259 pub(crate) policy: SchedulingPolicy,
260 pub(crate) normal_priority: NormalPriority,
264 pub(crate) realtime_priority: RealtimePriority,
267 pub(crate) reset_on_fork: bool,
268}
269
270impl SchedulerState {
271 pub fn is_default(&self) -> bool {
272 self == &Self::default()
273 }
274
275 pub fn from_binder(policy: u8, priority_or_nice: u8) -> Result<Self, Errno> {
281 let (policy, normal_priority, realtime_priority) = match policy as u32 {
282 SCHED_NORMAL => (
283 SchedulingPolicy::Normal,
284 NormalPriority::from_binder(priority_or_nice as i8)?,
285 RealtimePriority::NON_REAL_TIME,
286 ),
287 SCHED_BATCH => (
288 SchedulingPolicy::Batch,
289 NormalPriority::from_binder(priority_or_nice as i8)?,
290 RealtimePriority::NON_REAL_TIME,
291 ),
292 SCHED_FIFO => (
293 SchedulingPolicy::Fifo,
294 NormalPriority::default(),
295 SchedulingPolicy::Fifo.realtime_priority_from(priority_or_nice as i32)?,
296 ),
297 SCHED_RR => (
298 SchedulingPolicy::RoundRobin,
299 NormalPriority::default(),
300 SchedulingPolicy::RoundRobin.realtime_priority_from(priority_or_nice as i32)?,
301 ),
302 _ => return error!(EINVAL),
303 };
304 Ok(Self { policy, normal_priority, realtime_priority, reset_on_fork: false })
305 }
306
307 pub fn fork(self) -> Self {
308 if self.reset_on_fork {
309 let (policy, normal_priority, realtime_priority) = if self.is_realtime() {
310 (
316 SchedulingPolicy::Normal,
317 NormalPriority::default(),
318 RealtimePriority::NON_REAL_TIME,
319 )
320 } else {
321 (
326 self.policy,
327 std::cmp::min(self.normal_priority, NormalPriority::default()),
328 RealtimePriority::NON_REAL_TIME,
329 )
330 };
331 Self {
332 policy,
333 normal_priority,
334 realtime_priority,
335 reset_on_fork: false,
337 }
338 } else {
339 self
340 }
341 }
342
343 pub fn policy_for_sched_getscheduler(&self) -> u32 {
349 let mut base = match self.policy {
350 SchedulingPolicy::Normal => SCHED_NORMAL,
351 SchedulingPolicy::Batch => SCHED_BATCH,
352 SchedulingPolicy::Idle => SCHED_IDLE,
353 SchedulingPolicy::Fifo => SCHED_FIFO,
354 SchedulingPolicy::RoundRobin => SCHED_RR,
355 };
356 if self.reset_on_fork {
357 base |= SCHED_RESET_ON_FORK;
358 }
359 base
360 }
361
362 pub fn get_sched_param(&self) -> sched_param {
367 sched_param {
368 sched_priority: (if self.is_realtime() {
369 self.realtime_priority.value
370 } else {
371 RealtimePriority::NON_REAL_TIME_VALUE
372 }) as i32,
373 }
374 }
375
376 pub fn normal_priority(&self) -> NormalPriority {
377 self.normal_priority
378 }
379
380 pub fn is_realtime(&self) -> bool {
381 match self.policy {
382 SchedulingPolicy::Normal | SchedulingPolicy::Batch | SchedulingPolicy::Idle => false,
383 SchedulingPolicy::Fifo | SchedulingPolicy::RoundRobin => true,
384 }
385 }
386
387 fn role_name(&self) -> &'static str {
400 match self.policy {
401 SchedulingPolicy::Idle => FAIR_PRIORITY_ROLE_NAMES[0],
404
405 SchedulingPolicy::Normal => {
408 FAIR_PRIORITY_ROLE_NAMES[(self.normal_priority.value as usize / 2) + 6]
409 }
410 SchedulingPolicy::Batch => {
411 track_stub!(TODO("https://fxbug.dev/308055542"), "SCHED_BATCH hinting");
412 FAIR_PRIORITY_ROLE_NAMES[(self.normal_priority.value as usize / 2) + 6]
413 }
414
415 SchedulingPolicy::Fifo | SchedulingPolicy::RoundRobin => REALTIME_ROLE_NAME,
421 }
422 }
423
424 pub fn is_less_than_for_binder(&self, other: Self) -> bool {
427 match self.policy {
428 SchedulingPolicy::Fifo | SchedulingPolicy::RoundRobin => match other.policy {
429 SchedulingPolicy::Fifo | SchedulingPolicy::RoundRobin => {
430 self.realtime_priority < other.realtime_priority
431 }
432 SchedulingPolicy::Normal | SchedulingPolicy::Batch | SchedulingPolicy::Idle => {
433 false
434 }
435 },
436 SchedulingPolicy::Normal => match other.policy {
437 SchedulingPolicy::Fifo | SchedulingPolicy::RoundRobin => true,
438 SchedulingPolicy::Normal => {
439 self.normal_priority.value < other.normal_priority.value
440 }
441 SchedulingPolicy::Batch | SchedulingPolicy::Idle => false,
442 },
443 SchedulingPolicy::Batch => match other.policy {
444 SchedulingPolicy::Fifo
445 | SchedulingPolicy::RoundRobin
446 | SchedulingPolicy::Normal => true,
447 SchedulingPolicy::Batch => self.normal_priority.value < other.normal_priority.value,
448 SchedulingPolicy::Idle => false,
449 },
450 SchedulingPolicy::Idle => match other.policy {
452 SchedulingPolicy::Fifo
453 | SchedulingPolicy::RoundRobin
454 | SchedulingPolicy::Normal
455 | SchedulingPolicy::Batch => true,
456 SchedulingPolicy::Idle => false,
457 },
458 }
459 }
460}
461
462impl std::default::Default for SchedulerState {
463 fn default() -> Self {
464 Self {
465 policy: SchedulingPolicy::Normal,
466 normal_priority: NormalPriority::default(),
467 realtime_priority: RealtimePriority::NON_REAL_TIME,
468 reset_on_fork: false,
469 }
470 }
471}
472
473pub fn min_priority_for_sched_policy(policy: u32) -> Result<u8, Errno> {
474 Ok(match policy {
475 SCHED_DEADLINE => RealtimePriority::NON_REAL_TIME_VALUE,
476 _ => SchedulingPolicy::try_from(policy)?.realtime_priority_min(),
477 })
478}
479
480pub fn max_priority_for_sched_policy(policy: u32) -> Result<u8, Errno> {
481 Ok(match policy {
482 SCHED_DEADLINE => RealtimePriority::NON_REAL_TIME_VALUE,
483 _ => SchedulingPolicy::try_from(policy)?.realtime_priority_max(),
484 })
485}
486
487const FAIR_PRIORITY_ROLE_NAMES: [&str; 32] = [
491 "fuchsia.starnix.fair.0",
492 "fuchsia.starnix.fair.1",
493 "fuchsia.starnix.fair.2",
494 "fuchsia.starnix.fair.3",
495 "fuchsia.starnix.fair.4",
496 "fuchsia.starnix.fair.5",
497 "fuchsia.starnix.fair.6",
498 "fuchsia.starnix.fair.7",
499 "fuchsia.starnix.fair.8",
500 "fuchsia.starnix.fair.9",
501 "fuchsia.starnix.fair.10",
502 "fuchsia.starnix.fair.11",
503 "fuchsia.starnix.fair.12",
504 "fuchsia.starnix.fair.13",
505 "fuchsia.starnix.fair.14",
506 "fuchsia.starnix.fair.15",
507 "fuchsia.starnix.fair.16",
508 "fuchsia.starnix.fair.17",
509 "fuchsia.starnix.fair.18",
510 "fuchsia.starnix.fair.19",
511 "fuchsia.starnix.fair.20",
512 "fuchsia.starnix.fair.21",
513 "fuchsia.starnix.fair.22",
514 "fuchsia.starnix.fair.23",
515 "fuchsia.starnix.fair.24",
516 "fuchsia.starnix.fair.25",
517 "fuchsia.starnix.fair.26",
518 "fuchsia.starnix.fair.27",
519 "fuchsia.starnix.fair.28",
520 "fuchsia.starnix.fair.29",
521 "fuchsia.starnix.fair.30",
522 "fuchsia.starnix.fair.31",
523];
524const REALTIME_ROLE_NAME: &str = "fuchsia.starnix.realtime";
525#[cfg(test)]
528mod tests {
529 use super::*;
530 use assert_matches::assert_matches;
531
532 #[fuchsia::test]
533 fn default_role_name() {
534 assert_eq!(SchedulerState::default().role_name(), "fuchsia.starnix.fair.16");
535 }
536
537 #[fuchsia::test]
538 fn normal_with_non_default_nice_role_name() {
539 assert_eq!(
540 SchedulerState {
541 policy: SchedulingPolicy::Normal,
542 normal_priority: NormalPriority { value: 10 },
543 realtime_priority: RealtimePriority::NON_REAL_TIME,
544 reset_on_fork: false
545 }
546 .role_name(),
547 "fuchsia.starnix.fair.11"
548 );
549 assert_eq!(
550 SchedulerState {
551 policy: SchedulingPolicy::Normal,
552 normal_priority: NormalPriority { value: 27 },
553 realtime_priority: RealtimePriority::NON_REAL_TIME,
554 reset_on_fork: false
555 }
556 .role_name(),
557 "fuchsia.starnix.fair.19"
558 );
559 }
560
561 #[fuchsia::test]
562 fn fifo_role_name() {
563 assert_eq!(
564 SchedulerState {
565 policy: SchedulingPolicy::Fifo,
566 normal_priority: NormalPriority::default(),
567 realtime_priority: RealtimePriority { value: 1 },
568 reset_on_fork: false
569 }
570 .role_name(),
571 "fuchsia.starnix.realtime",
572 );
573 assert_eq!(
574 SchedulerState {
575 policy: SchedulingPolicy::Fifo,
576 normal_priority: NormalPriority::default(),
577 realtime_priority: RealtimePriority { value: 2 },
578 reset_on_fork: false
579 }
580 .role_name(),
581 "fuchsia.starnix.realtime",
582 );
583 assert_eq!(
584 SchedulerState {
585 policy: SchedulingPolicy::Fifo,
586 normal_priority: NormalPriority::default(),
587 realtime_priority: RealtimePriority { value: 99 },
588 reset_on_fork: false
589 }
590 .role_name(),
591 "fuchsia.starnix.realtime",
592 );
593 }
594
595 #[fuchsia::test]
596 fn idle_role_name() {
597 assert_eq!(
598 SchedulerState {
599 policy: SchedulingPolicy::Idle,
600 normal_priority: NormalPriority { value: 1 },
601 realtime_priority: RealtimePriority::NON_REAL_TIME,
602 reset_on_fork: false,
603 }
604 .role_name(),
605 "fuchsia.starnix.fair.0"
606 );
607 assert_eq!(
608 SchedulerState {
609 policy: SchedulingPolicy::Idle,
610 normal_priority: NormalPriority::default(),
611 realtime_priority: RealtimePriority::NON_REAL_TIME,
612 reset_on_fork: false,
613 }
614 .role_name(),
615 "fuchsia.starnix.fair.0"
616 );
617 assert_eq!(
618 SchedulerState {
619 policy: SchedulingPolicy::Idle,
620 normal_priority: NormalPriority { value: 40 },
621 realtime_priority: RealtimePriority::NON_REAL_TIME,
622 reset_on_fork: false,
623 }
624 .role_name(),
625 "fuchsia.starnix.fair.0"
626 );
627 }
628
629 #[fuchsia::test]
630 fn build_policy_from_binder() {
631 assert_matches!(SchedulerState::from_binder(SCHED_NORMAL as u8, 0), Ok(_));
632 assert_matches!(
633 SchedulerState::from_binder(SCHED_NORMAL as u8, ((-21) as i8) as u8),
634 Err(_)
635 );
636 assert_matches!(
637 SchedulerState::from_binder(SCHED_NORMAL as u8, ((-20) as i8) as u8),
638 Ok(SchedulerState {
639 policy: SchedulingPolicy::Normal,
640 normal_priority: NormalPriority { value: 40 },
641 realtime_priority: RealtimePriority::NON_REAL_TIME,
642 reset_on_fork: false,
643 })
644 );
645 assert_matches!(SchedulerState::from_binder(SCHED_NORMAL as u8, 1), Ok(_));
646 assert_matches!(SchedulerState::from_binder(SCHED_NORMAL as u8, 19), Ok(_));
647 assert_matches!(SchedulerState::from_binder(SCHED_NORMAL as u8, 20), Err(_));
648 assert_matches!(SchedulerState::from_binder(SCHED_FIFO as u8, 0), Err(_));
649 assert_matches!(SchedulerState::from_binder(SCHED_FIFO as u8, 1), Ok(_));
650 assert_matches!(SchedulerState::from_binder(SCHED_FIFO as u8, 99), Ok(_));
651 assert_matches!(SchedulerState::from_binder(SCHED_FIFO as u8, 100), Err(_));
652 assert_matches!(SchedulerState::from_binder(SCHED_RR as u8, 0), Err(_));
653 assert_matches!(SchedulerState::from_binder(SCHED_RR as u8, 1), Ok(_));
654 assert_matches!(SchedulerState::from_binder(SCHED_RR as u8, 99), Ok(_));
655 assert_matches!(SchedulerState::from_binder(SCHED_RR as u8, 100), Err(_));
656 assert_matches!(SchedulerState::from_binder(SCHED_BATCH as u8, 11), Ok(_));
657 assert_eq!(SchedulerState::from_binder(SCHED_IDLE as u8, 11), error!(EINVAL));
658 assert_matches!(SchedulerState::from_binder(42, 0), Err(_));
659 assert_matches!(SchedulerState::from_binder(42, 0), Err(_));
660 }
661
662 #[fuchsia::test]
665 fn is_less_than_for_binder() {
666 let rr_50 = SchedulerState {
667 policy: SchedulingPolicy::RoundRobin,
668 normal_priority: NormalPriority { value: 1 },
669 realtime_priority: RealtimePriority { value: 50 },
670 reset_on_fork: false,
671 };
672 let rr_40 = SchedulerState {
673 policy: SchedulingPolicy::RoundRobin,
674 normal_priority: NormalPriority { value: 1 },
675 realtime_priority: RealtimePriority { value: 40 },
676 reset_on_fork: false,
677 };
678 let fifo_50 = SchedulerState {
679 policy: SchedulingPolicy::Fifo,
680 normal_priority: NormalPriority { value: 1 },
681 realtime_priority: RealtimePriority { value: 50 },
682 reset_on_fork: false,
683 };
684 let fifo_40 = SchedulerState {
685 policy: SchedulingPolicy::Fifo,
686 normal_priority: NormalPriority { value: 1 },
687 realtime_priority: RealtimePriority { value: 40 },
688 reset_on_fork: false,
689 };
690 let normal_40 = SchedulerState {
691 policy: SchedulingPolicy::Normal,
692 normal_priority: NormalPriority { value: 40 },
693 realtime_priority: RealtimePriority::NON_REAL_TIME,
694 reset_on_fork: true,
695 };
696 let normal_10 = SchedulerState {
697 policy: SchedulingPolicy::Normal,
698 normal_priority: NormalPriority { value: 10 },
699 realtime_priority: RealtimePriority::NON_REAL_TIME,
700 reset_on_fork: true,
701 };
702 let batch_40 = SchedulerState {
703 policy: SchedulingPolicy::Batch,
704 normal_priority: NormalPriority { value: 40 },
705 realtime_priority: RealtimePriority::NON_REAL_TIME,
706 reset_on_fork: true,
707 };
708 let batch_30 = SchedulerState {
709 policy: SchedulingPolicy::Batch,
710 normal_priority: NormalPriority { value: 30 },
711 realtime_priority: RealtimePriority::NON_REAL_TIME,
712 reset_on_fork: true,
713 };
714 let idle_40 = SchedulerState {
715 policy: SchedulingPolicy::Idle,
716 normal_priority: NormalPriority { value: 40 },
717 realtime_priority: RealtimePriority::NON_REAL_TIME,
718 reset_on_fork: true,
719 };
720 let idle_30 = SchedulerState {
721 policy: SchedulingPolicy::Idle,
722 normal_priority: NormalPriority { value: 30 },
723 realtime_priority: RealtimePriority::NON_REAL_TIME,
724 reset_on_fork: true,
725 };
726 assert!(!fifo_50.is_less_than_for_binder(fifo_50));
727 assert!(!rr_50.is_less_than_for_binder(rr_50));
728 assert!(!fifo_50.is_less_than_for_binder(rr_50));
729 assert!(!rr_50.is_less_than_for_binder(fifo_50));
730 assert!(!fifo_50.is_less_than_for_binder(rr_40));
731 assert!(rr_40.is_less_than_for_binder(fifo_50));
732 assert!(!rr_50.is_less_than_for_binder(fifo_40));
733 assert!(fifo_40.is_less_than_for_binder(rr_50));
734 assert!(!fifo_40.is_less_than_for_binder(normal_40));
735 assert!(normal_40.is_less_than_for_binder(fifo_40));
736 assert!(!rr_40.is_less_than_for_binder(normal_40));
737 assert!(normal_40.is_less_than_for_binder(rr_40));
738 assert!(!normal_40.is_less_than_for_binder(normal_40));
739 assert!(!normal_40.is_less_than_for_binder(normal_10));
740 assert!(normal_10.is_less_than_for_binder(normal_40));
741 assert!(!normal_10.is_less_than_for_binder(batch_40));
742 assert!(batch_40.is_less_than_for_binder(normal_10));
743 assert!(!batch_40.is_less_than_for_binder(batch_40));
744 assert!(!batch_40.is_less_than_for_binder(batch_30));
745 assert!(batch_30.is_less_than_for_binder(batch_40));
746 assert!(!batch_30.is_less_than_for_binder(idle_40));
747 assert!(idle_40.is_less_than_for_binder(batch_30));
748 assert!(!idle_40.is_less_than_for_binder(idle_40));
749 assert!(!idle_40.is_less_than_for_binder(idle_30));
750 assert!(!idle_30.is_less_than_for_binder(idle_40));
751 }
752
753 #[fuchsia::test]
754 async fn role_overrides_non_realtime() {
755 crate::testing::spawn_kernel_and_run_sync(|_locked, current_task| {
756 let mut builder = RoleOverrides::new();
757 builder.add("my_task", "my_task", "overridden_role");
758 let overrides = builder.build().unwrap();
759 let manager = SchedulerManager { role_manager: None, role_overrides: overrides };
760
761 current_task.set_command_name(starnix_task_command::TaskCommand::new(b"my_task"));
762
763 let mut state = SchedulerState::default();
764 state.policy = SchedulingPolicy::Normal;
765
766 let role = manager.role_name_inner(current_task, state).expect("role_name");
767 assert_eq!(role, "overridden_role");
768 })
769 .await;
770 }
771}