1use crate::task::{RoleOverrides, Task};
6use fidl_fuchsia_scheduler::{
7 RoleManagerGetProfileForRoleRequest, RoleManagerMarker, RoleManagerSetRoleRequest,
8 RoleManagerSynchronousProxy, RoleName, RoleTarget, RoleType,
9};
10use fuchsia_component::client::connect_to_protocol_sync;
11use starnix_logging::{impossible_error, log_debug, log_error, 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};
17use std::collections::HashMap;
18use std::sync::Mutex;
19
20pub struct SchedulerManager {
21 role_manager: Option<RoleManagerSynchronousProxy>,
22 role_overrides: RoleOverrides,
23 profile_handle_cache: Mutex<HashMap<String, zx::Profile>>,
24}
25
26impl SchedulerManager {
27 pub fn new(role_overrides: RoleOverrides) -> SchedulerManager {
30 let profile_handle_cache = Mutex::new(HashMap::new());
31 let role_manager = fuchsia_runtime::with_thread_self(|thread| {
32 let role_manager = connect_to_protocol_sync::<RoleManagerMarker>().unwrap();
33 if let Err(e) = Self::set_thread_role_inner(
34 &role_manager,
35 thread,
36 SchedulerState::default().role_name(),
37 &profile_handle_cache,
38 ) {
39 log_debug!("Setting thread role failed ({e:?}), will not set thread priority.");
40 None
41 } else {
42 log_debug!("Thread role set successfully, scheduler manager initialized.");
43 Some(role_manager)
44 }
45 });
46
47 SchedulerManager { role_manager, role_overrides, profile_handle_cache }
48 }
49
50 pub fn empty_for_tests() -> Self {
52 Self {
53 role_manager: None,
54 role_overrides: RoleOverrides::new().build().unwrap(),
55 profile_handle_cache: Mutex::new(HashMap::new()),
56 }
57 }
58
59 pub fn role_name(&self, task: &Task) -> Result<&str, Errno> {
62 let scheduler_state = task.read().scheduler_state;
63 self.role_name_inner(task, scheduler_state)
64 }
65
66 fn role_name_inner(&self, task: &Task, scheduler_state: SchedulerState) -> Result<&str, Errno> {
67 let process_name = task
68 .thread_group()
69 .read()
70 .get_task(task.thread_group().leader)
71 .ok_or_else(|| errno!(EINVAL))?
72 .command();
73 let thread_name = task.command();
74 if let Some(name) = self.role_overrides.get_role_name(&process_name, &thread_name) {
75 return Ok(name);
76 }
77 Ok(scheduler_state.role_name())
78 }
79
80 pub fn set_thread_role(
85 &self,
86 task: &Task,
87 scheduler_state: SchedulerState,
88 ) -> Result<(), Errno> {
89 let Some(role_manager) = self.role_manager.as_ref() else {
90 log_debug!("no role manager for setting role");
91 return Ok(());
92 };
93
94 let role_name = self.role_name_inner(task, scheduler_state)?;
95 let live = match task.live() {
96 Ok(live) => live,
97 Err(_) => {
98 log_debug!("thread role update requested for task without live state, skipping");
99 return Ok(());
100 }
101 };
102 let thread = live.thread.read();
103 let Some(thread) = thread.as_ref() else {
104 log_debug!("thread role update requested for task without thread, skipping");
105 return Ok(());
106 };
107 Self::set_thread_role_inner(role_manager, thread, role_name, &self.profile_handle_cache)
108 }
109
110 fn set_thread_role_inner(
111 role_manager: &RoleManagerSynchronousProxy,
112 thread: &zx::Thread,
113 role_name: &str,
114 cache: &Mutex<HashMap<String, zx::Profile>>,
115 ) -> Result<(), Errno> {
116 log_debug!(role_name; "setting thread role");
117
118 {
119 let params = cache.lock().unwrap();
120 if let Some(profile) = params.get(role_name) {
121 match thread.set_profile(&profile, 0) {
122 Ok(_) => return Ok(()),
123 Err(e) => log_error!("Failed to set role profile {:?}", e),
124 }
125 }
126 }
127
128 let request = RoleManagerGetProfileForRoleRequest {
129 role: Some(RoleName { role: role_name.to_string() }),
130 target: Some(RoleType::Task),
131 ..Default::default()
132 };
133 match role_manager.get_profile_for_role(request, zx::MonotonicInstant::INFINITE) {
134 Ok(Ok(response)) => {
135 let Some(profile) = response.profile else {
136 log_warn!("GetRole returned success but no profile handle");
137 return error!(EINVAL);
138 };
139
140 if let Err(e) = thread.set_profile(&profile, 0) {
141 log_warn!(e:%; "Failed to set thread profile from handle");
142 return error!(EINVAL);
143 }
144 cache.lock().unwrap().insert(role_name.to_string(), profile);
145 Ok(())
146 }
147 Ok(Err(e)) => {
148 log_warn!(e:%; "GetRole returned error");
149 Self::set_thread_role_legacy(role_manager, thread, role_name)
150 }
151 Err(e) => {
152 log_warn!(e:%; "GetRole FIDL call failed");
153 Self::set_thread_role_legacy(role_manager, thread, role_name)
154 }
155 }
156 }
157
158 fn set_thread_role_legacy(
159 role_manager: &RoleManagerSynchronousProxy,
160 thread: &zx::Thread,
161 role_name: &str,
162 ) -> Result<(), Errno> {
163 let thread = thread.duplicate_handle(zx::Rights::SAME_RIGHTS).map_err(impossible_error)?;
164 let request = RoleManagerSetRoleRequest {
165 target: Some(RoleTarget::Thread(thread)),
166 role: Some(RoleName { role: role_name.to_string() }),
167 ..Default::default()
168 };
169 let _ = role_manager.set_role(request, zx::MonotonicInstant::INFINITE).map_err(|err| {
170 log_warn!(err:%; "Unable to set thread role.");
171 errno!(EINVAL)
172 })?;
173 Ok(())
174 }
175}
176
177#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
182pub struct NormalPriority {
183 value: u8,
186}
187
188impl NormalPriority {
189 const MIN_VALUE: u8 = 1;
190 const DEFAULT_VALUE: u8 = 20;
191 const MAX_VALUE: u8 = 40;
192
193 pub(crate) fn from_setpriority_syscall(user_nice: i32) -> Self {
200 Self {
201 value: (Self::DEFAULT_VALUE as i32)
202 .saturating_sub(user_nice)
203 .clamp(Self::MIN_VALUE as i32, Self::MAX_VALUE as i32) as u8,
204 }
205 }
206
207 pub fn from_binder(user_nice: i8) -> Result<Self, Errno> {
214 let value = (Self::DEFAULT_VALUE as i8).saturating_sub(user_nice);
215 if value < (Self::MIN_VALUE as i8) || value > (Self::MAX_VALUE as i8) {
216 return error!(EINVAL);
217 }
218 Ok(Self { value: u8::try_from(value).expect("normal priority should fit in a u8") })
219 }
220
221 pub fn as_nice(&self) -> i8 {
224 (Self::DEFAULT_VALUE as i8) - (self.value as i8)
225 }
226
227 pub(crate) fn raw_priority(&self) -> u8 {
230 self.value
231 }
232
233 pub(crate) fn exceeds(&self, limit: u64) -> bool {
235 limit < (self.value as u64)
236 }
237}
238
239impl std::default::Default for NormalPriority {
240 fn default() -> Self {
241 Self { value: Self::DEFAULT_VALUE }
242 }
243}
244
245#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
249pub(crate) struct RealtimePriority {
250 value: u8,
254}
255
256impl RealtimePriority {
257 const NON_REAL_TIME_VALUE: u8 = 0;
258 const MIN_VALUE: u8 = 1;
259 const MAX_VALUE: u8 = 99;
260
261 const NON_REAL_TIME: RealtimePriority = RealtimePriority { value: Self::NON_REAL_TIME_VALUE };
262
263 pub(crate) fn exceeds(&self, limit: u64) -> bool {
264 limit < (self.value as u64)
265 }
266}
267
268#[derive(Clone, Copy, Debug, Eq, PartialEq)]
270pub(crate) enum SchedulingPolicy {
271 Normal,
272 Batch,
273 Idle,
274 Fifo,
275 RoundRobin,
276}
277
278impl SchedulingPolicy {
279 fn realtime_priority_min(&self) -> u8 {
280 match self {
281 Self::Normal | Self::Batch | Self::Idle => RealtimePriority::NON_REAL_TIME_VALUE,
282 Self::Fifo | Self::RoundRobin => RealtimePriority::MIN_VALUE,
283 }
284 }
285
286 fn realtime_priority_max(&self) -> u8 {
287 match self {
288 Self::Normal | Self::Batch | Self::Idle => RealtimePriority::NON_REAL_TIME_VALUE,
289 Self::Fifo | Self::RoundRobin => RealtimePriority::MAX_VALUE,
290 }
291 }
292
293 pub(crate) fn realtime_priority_from(&self, priority: i32) -> Result<RealtimePriority, Errno> {
294 let priority = u8::try_from(priority).map_err(|_| errno!(EINVAL))?;
295 if priority < self.realtime_priority_min() || priority > self.realtime_priority_max() {
296 return error!(EINVAL);
297 }
298 Ok(RealtimePriority { value: priority })
299 }
300}
301
302impl TryFrom<u32> for SchedulingPolicy {
303 type Error = Errno;
304
305 fn try_from(value: u32) -> Result<Self, Errno> {
306 Ok(match value {
307 SCHED_NORMAL => Self::Normal,
308 SCHED_BATCH => Self::Batch,
309 SCHED_IDLE => Self::Idle,
310 SCHED_FIFO => Self::Fifo,
311 SCHED_RR => Self::RoundRobin,
312 _ => {
313 return error!(EINVAL);
314 }
315 })
316 }
317}
318
319#[derive(Clone, Copy, Debug, Eq, PartialEq)]
320pub struct SchedulerState {
321 pub(crate) policy: SchedulingPolicy,
322 pub(crate) normal_priority: NormalPriority,
326 pub(crate) realtime_priority: RealtimePriority,
329 pub(crate) reset_on_fork: bool,
330}
331
332impl SchedulerState {
333 pub fn is_default(&self) -> bool {
334 self == &Self::default()
335 }
336
337 pub fn from_binder(policy: u8, priority_or_nice: u8) -> Result<Self, Errno> {
343 let (policy, normal_priority, realtime_priority) = match policy as u32 {
344 SCHED_NORMAL => (
345 SchedulingPolicy::Normal,
346 NormalPriority::from_binder(priority_or_nice as i8)?,
347 RealtimePriority::NON_REAL_TIME,
348 ),
349 SCHED_BATCH => (
350 SchedulingPolicy::Batch,
351 NormalPriority::from_binder(priority_or_nice as i8)?,
352 RealtimePriority::NON_REAL_TIME,
353 ),
354 SCHED_FIFO => (
355 SchedulingPolicy::Fifo,
356 NormalPriority::default(),
357 SchedulingPolicy::Fifo.realtime_priority_from(priority_or_nice as i32)?,
358 ),
359 SCHED_RR => (
360 SchedulingPolicy::RoundRobin,
361 NormalPriority::default(),
362 SchedulingPolicy::RoundRobin.realtime_priority_from(priority_or_nice as i32)?,
363 ),
364 _ => return error!(EINVAL),
365 };
366 Ok(Self { policy, normal_priority, realtime_priority, reset_on_fork: false })
367 }
368
369 pub fn fork(self) -> Self {
370 if self.reset_on_fork {
371 let (policy, normal_priority, realtime_priority) = if self.is_realtime() {
372 (
378 SchedulingPolicy::Normal,
379 NormalPriority::default(),
380 RealtimePriority::NON_REAL_TIME,
381 )
382 } else {
383 (
388 self.policy,
389 std::cmp::min(self.normal_priority, NormalPriority::default()),
390 RealtimePriority::NON_REAL_TIME,
391 )
392 };
393 Self {
394 policy,
395 normal_priority,
396 realtime_priority,
397 reset_on_fork: false,
399 }
400 } else {
401 self
402 }
403 }
404
405 pub fn policy_for_sched_getscheduler(&self) -> u32 {
411 let mut base = match self.policy {
412 SchedulingPolicy::Normal => SCHED_NORMAL,
413 SchedulingPolicy::Batch => SCHED_BATCH,
414 SchedulingPolicy::Idle => SCHED_IDLE,
415 SchedulingPolicy::Fifo => SCHED_FIFO,
416 SchedulingPolicy::RoundRobin => SCHED_RR,
417 };
418 if self.reset_on_fork {
419 base |= SCHED_RESET_ON_FORK;
420 }
421 base
422 }
423
424 pub fn get_sched_param(&self) -> sched_param {
429 sched_param {
430 sched_priority: (if self.is_realtime() {
431 self.realtime_priority.value
432 } else {
433 RealtimePriority::NON_REAL_TIME_VALUE
434 }) as i32,
435 }
436 }
437
438 pub fn normal_priority(&self) -> NormalPriority {
439 self.normal_priority
440 }
441
442 pub fn is_realtime(&self) -> bool {
443 match self.policy {
444 SchedulingPolicy::Normal | SchedulingPolicy::Batch | SchedulingPolicy::Idle => false,
445 SchedulingPolicy::Fifo | SchedulingPolicy::RoundRobin => true,
446 }
447 }
448
449 fn role_name(&self) -> &'static str {
462 match self.policy {
463 SchedulingPolicy::Idle => FAIR_PRIORITY_ROLE_NAMES[0],
466
467 SchedulingPolicy::Normal => {
470 FAIR_PRIORITY_ROLE_NAMES[(self.normal_priority.value as usize / 2) + 6]
471 }
472 SchedulingPolicy::Batch => {
473 track_stub!(TODO("https://fxbug.dev/308055542"), "SCHED_BATCH hinting");
474 FAIR_PRIORITY_ROLE_NAMES[(self.normal_priority.value as usize / 2) + 6]
475 }
476
477 SchedulingPolicy::Fifo | SchedulingPolicy::RoundRobin => REALTIME_ROLE_NAME,
483 }
484 }
485
486 pub fn is_less_than_for_binder(&self, other: Self) -> bool {
489 match self.policy {
490 SchedulingPolicy::Fifo | SchedulingPolicy::RoundRobin => match other.policy {
491 SchedulingPolicy::Fifo | SchedulingPolicy::RoundRobin => {
492 self.realtime_priority < other.realtime_priority
493 }
494 SchedulingPolicy::Normal | SchedulingPolicy::Batch | SchedulingPolicy::Idle => {
495 false
496 }
497 },
498 SchedulingPolicy::Normal => match other.policy {
499 SchedulingPolicy::Fifo | SchedulingPolicy::RoundRobin => true,
500 SchedulingPolicy::Normal => {
501 self.normal_priority.value < other.normal_priority.value
502 }
503 SchedulingPolicy::Batch | SchedulingPolicy::Idle => false,
504 },
505 SchedulingPolicy::Batch => match other.policy {
506 SchedulingPolicy::Fifo
507 | SchedulingPolicy::RoundRobin
508 | SchedulingPolicy::Normal => true,
509 SchedulingPolicy::Batch => self.normal_priority.value < other.normal_priority.value,
510 SchedulingPolicy::Idle => false,
511 },
512 SchedulingPolicy::Idle => match other.policy {
514 SchedulingPolicy::Fifo
515 | SchedulingPolicy::RoundRobin
516 | SchedulingPolicy::Normal
517 | SchedulingPolicy::Batch => true,
518 SchedulingPolicy::Idle => false,
519 },
520 }
521 }
522}
523
524impl std::default::Default for SchedulerState {
525 fn default() -> Self {
526 Self {
527 policy: SchedulingPolicy::Normal,
528 normal_priority: NormalPriority::default(),
529 realtime_priority: RealtimePriority::NON_REAL_TIME,
530 reset_on_fork: false,
531 }
532 }
533}
534
535pub fn min_priority_for_sched_policy(policy: u32) -> Result<u8, Errno> {
536 Ok(match policy {
537 SCHED_DEADLINE => RealtimePriority::NON_REAL_TIME_VALUE,
538 _ => SchedulingPolicy::try_from(policy)?.realtime_priority_min(),
539 })
540}
541
542pub fn max_priority_for_sched_policy(policy: u32) -> Result<u8, Errno> {
543 Ok(match policy {
544 SCHED_DEADLINE => RealtimePriority::NON_REAL_TIME_VALUE,
545 _ => SchedulingPolicy::try_from(policy)?.realtime_priority_max(),
546 })
547}
548
549const FAIR_PRIORITY_ROLE_NAMES: [&str; 32] = [
553 "fuchsia.starnix.fair.0",
554 "fuchsia.starnix.fair.1",
555 "fuchsia.starnix.fair.2",
556 "fuchsia.starnix.fair.3",
557 "fuchsia.starnix.fair.4",
558 "fuchsia.starnix.fair.5",
559 "fuchsia.starnix.fair.6",
560 "fuchsia.starnix.fair.7",
561 "fuchsia.starnix.fair.8",
562 "fuchsia.starnix.fair.9",
563 "fuchsia.starnix.fair.10",
564 "fuchsia.starnix.fair.11",
565 "fuchsia.starnix.fair.12",
566 "fuchsia.starnix.fair.13",
567 "fuchsia.starnix.fair.14",
568 "fuchsia.starnix.fair.15",
569 "fuchsia.starnix.fair.16",
570 "fuchsia.starnix.fair.17",
571 "fuchsia.starnix.fair.18",
572 "fuchsia.starnix.fair.19",
573 "fuchsia.starnix.fair.20",
574 "fuchsia.starnix.fair.21",
575 "fuchsia.starnix.fair.22",
576 "fuchsia.starnix.fair.23",
577 "fuchsia.starnix.fair.24",
578 "fuchsia.starnix.fair.25",
579 "fuchsia.starnix.fair.26",
580 "fuchsia.starnix.fair.27",
581 "fuchsia.starnix.fair.28",
582 "fuchsia.starnix.fair.29",
583 "fuchsia.starnix.fair.30",
584 "fuchsia.starnix.fair.31",
585];
586const REALTIME_ROLE_NAME: &str = "fuchsia.starnix.realtime";
587#[cfg(test)]
590mod tests {
591 use super::*;
592 use assert_matches::assert_matches;
593
594 #[fuchsia::test]
595 fn default_role_name() {
596 assert_eq!(SchedulerState::default().role_name(), "fuchsia.starnix.fair.16");
597 }
598
599 #[fuchsia::test]
600 fn normal_with_non_default_nice_role_name() {
601 assert_eq!(
602 SchedulerState {
603 policy: SchedulingPolicy::Normal,
604 normal_priority: NormalPriority { value: 10 },
605 realtime_priority: RealtimePriority::NON_REAL_TIME,
606 reset_on_fork: false
607 }
608 .role_name(),
609 "fuchsia.starnix.fair.11"
610 );
611 assert_eq!(
612 SchedulerState {
613 policy: SchedulingPolicy::Normal,
614 normal_priority: NormalPriority { value: 27 },
615 realtime_priority: RealtimePriority::NON_REAL_TIME,
616 reset_on_fork: false
617 }
618 .role_name(),
619 "fuchsia.starnix.fair.19"
620 );
621 }
622
623 #[fuchsia::test]
624 fn fifo_role_name() {
625 assert_eq!(
626 SchedulerState {
627 policy: SchedulingPolicy::Fifo,
628 normal_priority: NormalPriority::default(),
629 realtime_priority: RealtimePriority { value: 1 },
630 reset_on_fork: false
631 }
632 .role_name(),
633 "fuchsia.starnix.realtime",
634 );
635 assert_eq!(
636 SchedulerState {
637 policy: SchedulingPolicy::Fifo,
638 normal_priority: NormalPriority::default(),
639 realtime_priority: RealtimePriority { value: 2 },
640 reset_on_fork: false
641 }
642 .role_name(),
643 "fuchsia.starnix.realtime",
644 );
645 assert_eq!(
646 SchedulerState {
647 policy: SchedulingPolicy::Fifo,
648 normal_priority: NormalPriority::default(),
649 realtime_priority: RealtimePriority { value: 99 },
650 reset_on_fork: false
651 }
652 .role_name(),
653 "fuchsia.starnix.realtime",
654 );
655 }
656
657 #[fuchsia::test]
658 fn idle_role_name() {
659 assert_eq!(
660 SchedulerState {
661 policy: SchedulingPolicy::Idle,
662 normal_priority: NormalPriority { value: 1 },
663 realtime_priority: RealtimePriority::NON_REAL_TIME,
664 reset_on_fork: false,
665 }
666 .role_name(),
667 "fuchsia.starnix.fair.0"
668 );
669 assert_eq!(
670 SchedulerState {
671 policy: SchedulingPolicy::Idle,
672 normal_priority: NormalPriority::default(),
673 realtime_priority: RealtimePriority::NON_REAL_TIME,
674 reset_on_fork: false,
675 }
676 .role_name(),
677 "fuchsia.starnix.fair.0"
678 );
679 assert_eq!(
680 SchedulerState {
681 policy: SchedulingPolicy::Idle,
682 normal_priority: NormalPriority { value: 40 },
683 realtime_priority: RealtimePriority::NON_REAL_TIME,
684 reset_on_fork: false,
685 }
686 .role_name(),
687 "fuchsia.starnix.fair.0"
688 );
689 }
690
691 #[fuchsia::test]
692 fn build_policy_from_binder() {
693 assert_matches!(SchedulerState::from_binder(SCHED_NORMAL as u8, 0), Ok(_));
694 assert_matches!(
695 SchedulerState::from_binder(SCHED_NORMAL as u8, ((-21) as i8) as u8),
696 Err(_)
697 );
698 assert_matches!(
699 SchedulerState::from_binder(SCHED_NORMAL as u8, ((-20) as i8) as u8),
700 Ok(SchedulerState {
701 policy: SchedulingPolicy::Normal,
702 normal_priority: NormalPriority { value: 40 },
703 realtime_priority: RealtimePriority::NON_REAL_TIME,
704 reset_on_fork: false,
705 })
706 );
707 assert_matches!(SchedulerState::from_binder(SCHED_NORMAL as u8, 1), Ok(_));
708 assert_matches!(SchedulerState::from_binder(SCHED_NORMAL as u8, 19), Ok(_));
709 assert_matches!(SchedulerState::from_binder(SCHED_NORMAL as u8, 20), Err(_));
710 assert_matches!(SchedulerState::from_binder(SCHED_FIFO as u8, 0), Err(_));
711 assert_matches!(SchedulerState::from_binder(SCHED_FIFO as u8, 1), Ok(_));
712 assert_matches!(SchedulerState::from_binder(SCHED_FIFO as u8, 99), Ok(_));
713 assert_matches!(SchedulerState::from_binder(SCHED_FIFO as u8, 100), Err(_));
714 assert_matches!(SchedulerState::from_binder(SCHED_RR as u8, 0), Err(_));
715 assert_matches!(SchedulerState::from_binder(SCHED_RR as u8, 1), Ok(_));
716 assert_matches!(SchedulerState::from_binder(SCHED_RR as u8, 99), Ok(_));
717 assert_matches!(SchedulerState::from_binder(SCHED_RR as u8, 100), Err(_));
718 assert_matches!(SchedulerState::from_binder(SCHED_BATCH as u8, 11), Ok(_));
719 assert_eq!(SchedulerState::from_binder(SCHED_IDLE as u8, 11), error!(EINVAL));
720 assert_matches!(SchedulerState::from_binder(42, 0), Err(_));
721 assert_matches!(SchedulerState::from_binder(42, 0), Err(_));
722 }
723
724 #[fuchsia::test]
727 fn is_less_than_for_binder() {
728 let rr_50 = SchedulerState {
729 policy: SchedulingPolicy::RoundRobin,
730 normal_priority: NormalPriority { value: 1 },
731 realtime_priority: RealtimePriority { value: 50 },
732 reset_on_fork: false,
733 };
734 let rr_40 = SchedulerState {
735 policy: SchedulingPolicy::RoundRobin,
736 normal_priority: NormalPriority { value: 1 },
737 realtime_priority: RealtimePriority { value: 40 },
738 reset_on_fork: false,
739 };
740 let fifo_50 = SchedulerState {
741 policy: SchedulingPolicy::Fifo,
742 normal_priority: NormalPriority { value: 1 },
743 realtime_priority: RealtimePriority { value: 50 },
744 reset_on_fork: false,
745 };
746 let fifo_40 = SchedulerState {
747 policy: SchedulingPolicy::Fifo,
748 normal_priority: NormalPriority { value: 1 },
749 realtime_priority: RealtimePriority { value: 40 },
750 reset_on_fork: false,
751 };
752 let normal_40 = SchedulerState {
753 policy: SchedulingPolicy::Normal,
754 normal_priority: NormalPriority { value: 40 },
755 realtime_priority: RealtimePriority::NON_REAL_TIME,
756 reset_on_fork: true,
757 };
758 let normal_10 = SchedulerState {
759 policy: SchedulingPolicy::Normal,
760 normal_priority: NormalPriority { value: 10 },
761 realtime_priority: RealtimePriority::NON_REAL_TIME,
762 reset_on_fork: true,
763 };
764 let batch_40 = SchedulerState {
765 policy: SchedulingPolicy::Batch,
766 normal_priority: NormalPriority { value: 40 },
767 realtime_priority: RealtimePriority::NON_REAL_TIME,
768 reset_on_fork: true,
769 };
770 let batch_30 = SchedulerState {
771 policy: SchedulingPolicy::Batch,
772 normal_priority: NormalPriority { value: 30 },
773 realtime_priority: RealtimePriority::NON_REAL_TIME,
774 reset_on_fork: true,
775 };
776 let idle_40 = SchedulerState {
777 policy: SchedulingPolicy::Idle,
778 normal_priority: NormalPriority { value: 40 },
779 realtime_priority: RealtimePriority::NON_REAL_TIME,
780 reset_on_fork: true,
781 };
782 let idle_30 = SchedulerState {
783 policy: SchedulingPolicy::Idle,
784 normal_priority: NormalPriority { value: 30 },
785 realtime_priority: RealtimePriority::NON_REAL_TIME,
786 reset_on_fork: true,
787 };
788 assert!(!fifo_50.is_less_than_for_binder(fifo_50));
789 assert!(!rr_50.is_less_than_for_binder(rr_50));
790 assert!(!fifo_50.is_less_than_for_binder(rr_50));
791 assert!(!rr_50.is_less_than_for_binder(fifo_50));
792 assert!(!fifo_50.is_less_than_for_binder(rr_40));
793 assert!(rr_40.is_less_than_for_binder(fifo_50));
794 assert!(!rr_50.is_less_than_for_binder(fifo_40));
795 assert!(fifo_40.is_less_than_for_binder(rr_50));
796 assert!(!fifo_40.is_less_than_for_binder(normal_40));
797 assert!(normal_40.is_less_than_for_binder(fifo_40));
798 assert!(!rr_40.is_less_than_for_binder(normal_40));
799 assert!(normal_40.is_less_than_for_binder(rr_40));
800 assert!(!normal_40.is_less_than_for_binder(normal_40));
801 assert!(!normal_40.is_less_than_for_binder(normal_10));
802 assert!(normal_10.is_less_than_for_binder(normal_40));
803 assert!(!normal_10.is_less_than_for_binder(batch_40));
804 assert!(batch_40.is_less_than_for_binder(normal_10));
805 assert!(!batch_40.is_less_than_for_binder(batch_40));
806 assert!(!batch_40.is_less_than_for_binder(batch_30));
807 assert!(batch_30.is_less_than_for_binder(batch_40));
808 assert!(!batch_30.is_less_than_for_binder(idle_40));
809 assert!(idle_40.is_less_than_for_binder(batch_30));
810 assert!(!idle_40.is_less_than_for_binder(idle_40));
811 assert!(!idle_40.is_less_than_for_binder(idle_30));
812 assert!(!idle_30.is_less_than_for_binder(idle_40));
813 }
814
815 #[fuchsia::test]
816 async fn role_overrides_non_realtime() {
817 crate::testing::spawn_kernel_and_run_sync(|_locked, current_task| {
818 let mut builder = RoleOverrides::new();
819 builder.add("my_task", "my_task", "overridden_role");
820 let overrides = builder.build().unwrap();
821 let manager = SchedulerManager {
822 role_manager: None,
823 role_overrides: overrides,
824 profile_handle_cache: Mutex::new(HashMap::new()),
825 };
826
827 current_task.set_command_name(starnix_task_command::TaskCommand::new(b"my_task"));
828
829 let mut state = SchedulerState::default();
830 state.policy = SchedulingPolicy::Normal;
831
832 let role = manager.role_name_inner(current_task, state).expect("role_name");
833 assert_eq!(role, "overridden_role");
834 })
835 .await;
836 }
837}