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 running_state = match task.running_state() {
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 Some(zircon_thread) = running_state.thread.get() else {
103 log_debug!("thread role update requested for task without thread, skipping");
104 return Ok(());
105 };
106 Self::set_thread_role_inner(
107 role_manager,
108 &zircon_thread.thread,
109 role_name,
110 &self.profile_handle_cache,
111 )
112 }
113
114 fn set_thread_role_inner(
115 role_manager: &RoleManagerSynchronousProxy,
116 thread: &zx::Thread,
117 role_name: &str,
118 cache: &Mutex<HashMap<String, zx::Profile>>,
119 ) -> Result<(), Errno> {
120 log_debug!(role_name; "setting thread role");
121
122 {
123 let params = cache.lock().unwrap();
124 if let Some(profile) = params.get(role_name) {
125 match thread.set_profile(&profile, 0) {
126 Ok(_) => return Ok(()),
127 Err(e) => log_error!("Failed to set role profile {:?}", e),
128 }
129 }
130 }
131
132 let request = RoleManagerGetProfileForRoleRequest {
133 role: Some(RoleName { role: role_name.to_string() }),
134 target: Some(RoleType::Task),
135 ..Default::default()
136 };
137 match role_manager.get_profile_for_role(request, zx::MonotonicInstant::INFINITE) {
138 Ok(Ok(response)) => {
139 let Some(profile) = response.profile else {
140 log_warn!("GetRole returned success but no profile handle");
141 return error!(EINVAL);
142 };
143
144 if let Err(e) = thread.set_profile(&profile, 0) {
145 log_warn!(e:%; "Failed to set thread profile from handle");
146 return error!(EINVAL);
147 }
148 cache.lock().unwrap().insert(role_name.to_string(), profile);
149 Ok(())
150 }
151 Ok(Err(e)) => {
152 log_warn!(e:%; "GetRole returned error");
153 Self::set_thread_role_legacy(role_manager, thread, role_name)
154 }
155 Err(e) => {
156 log_warn!(e:%; "GetRole FIDL call failed");
157 Self::set_thread_role_legacy(role_manager, thread, role_name)
158 }
159 }
160 }
161
162 fn set_thread_role_legacy(
163 role_manager: &RoleManagerSynchronousProxy,
164 thread: &zx::Thread,
165 role_name: &str,
166 ) -> Result<(), Errno> {
167 let thread = thread.duplicate_handle(zx::Rights::SAME_RIGHTS).map_err(impossible_error)?;
168 let request = RoleManagerSetRoleRequest {
169 target: Some(RoleTarget::Thread(thread)),
170 role: Some(RoleName { role: role_name.to_string() }),
171 ..Default::default()
172 };
173 let _ = role_manager.set_role(request, zx::MonotonicInstant::INFINITE).map_err(|err| {
174 log_warn!(err:%; "Unable to set thread role.");
175 errno!(EINVAL)
176 })?;
177 Ok(())
178 }
179}
180
181#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
186pub struct NormalPriority {
187 value: u8,
190}
191
192impl NormalPriority {
193 const MIN_VALUE: u8 = 1;
194 const DEFAULT_VALUE: u8 = 20;
195 const MAX_VALUE: u8 = 40;
196
197 pub(crate) fn from_setpriority_syscall(user_nice: i32) -> Self {
204 Self {
205 value: (Self::DEFAULT_VALUE as i32)
206 .saturating_sub(user_nice)
207 .clamp(Self::MIN_VALUE as i32, Self::MAX_VALUE as i32) as u8,
208 }
209 }
210
211 pub fn from_binder(user_nice: i8) -> Result<Self, Errno> {
218 let value = (Self::DEFAULT_VALUE as i8).saturating_sub(user_nice);
219 if value < (Self::MIN_VALUE as i8) || value > (Self::MAX_VALUE as i8) {
220 return error!(EINVAL);
221 }
222 Ok(Self { value: u8::try_from(value).expect("normal priority should fit in a u8") })
223 }
224
225 pub fn as_nice(&self) -> i8 {
228 (Self::DEFAULT_VALUE as i8) - (self.value as i8)
229 }
230
231 pub(crate) fn raw_priority(&self) -> u8 {
234 self.value
235 }
236
237 pub(crate) fn exceeds(&self, limit: u64) -> bool {
239 limit < (self.value as u64)
240 }
241}
242
243impl std::default::Default for NormalPriority {
244 fn default() -> Self {
245 Self { value: Self::DEFAULT_VALUE }
246 }
247}
248
249#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
253pub(crate) struct RealtimePriority {
254 value: u8,
258}
259
260impl RealtimePriority {
261 const NON_REAL_TIME_VALUE: u8 = 0;
262 const MIN_VALUE: u8 = 1;
263 const MAX_VALUE: u8 = 99;
264
265 const NON_REAL_TIME: RealtimePriority = RealtimePriority { value: Self::NON_REAL_TIME_VALUE };
266
267 pub(crate) fn exceeds(&self, limit: u64) -> bool {
268 limit < (self.value as u64)
269 }
270}
271
272#[derive(Clone, Copy, Debug, Eq, PartialEq)]
274pub(crate) enum SchedulingPolicy {
275 Normal,
276 Batch,
277 Idle,
278 Fifo,
279 RoundRobin,
280}
281
282impl SchedulingPolicy {
283 fn realtime_priority_min(&self) -> u8 {
284 match self {
285 Self::Normal | Self::Batch | Self::Idle => RealtimePriority::NON_REAL_TIME_VALUE,
286 Self::Fifo | Self::RoundRobin => RealtimePriority::MIN_VALUE,
287 }
288 }
289
290 fn realtime_priority_max(&self) -> u8 {
291 match self {
292 Self::Normal | Self::Batch | Self::Idle => RealtimePriority::NON_REAL_TIME_VALUE,
293 Self::Fifo | Self::RoundRobin => RealtimePriority::MAX_VALUE,
294 }
295 }
296
297 pub(crate) fn realtime_priority_from(&self, priority: i32) -> Result<RealtimePriority, Errno> {
298 let priority = u8::try_from(priority).map_err(|_| errno!(EINVAL))?;
299 if priority < self.realtime_priority_min() || priority > self.realtime_priority_max() {
300 return error!(EINVAL);
301 }
302 Ok(RealtimePriority { value: priority })
303 }
304}
305
306impl TryFrom<u32> for SchedulingPolicy {
307 type Error = Errno;
308
309 fn try_from(value: u32) -> Result<Self, Errno> {
310 Ok(match value {
311 SCHED_NORMAL => Self::Normal,
312 SCHED_BATCH => Self::Batch,
313 SCHED_IDLE => Self::Idle,
314 SCHED_FIFO => Self::Fifo,
315 SCHED_RR => Self::RoundRobin,
316 _ => {
317 return error!(EINVAL);
318 }
319 })
320 }
321}
322
323#[derive(Clone, Copy, Debug, Eq, PartialEq)]
324pub struct SchedulerState {
325 pub(crate) policy: SchedulingPolicy,
326 pub(crate) normal_priority: NormalPriority,
330 pub(crate) realtime_priority: RealtimePriority,
333 pub(crate) reset_on_fork: bool,
334}
335
336impl SchedulerState {
337 pub fn is_default(&self) -> bool {
338 self == &Self::default()
339 }
340
341 pub fn from_binder(policy: u8, priority_or_nice: u8) -> Result<Self, Errno> {
347 let (policy, normal_priority, realtime_priority) = match policy as u32 {
348 SCHED_NORMAL => (
349 SchedulingPolicy::Normal,
350 NormalPriority::from_binder(priority_or_nice as i8)?,
351 RealtimePriority::NON_REAL_TIME,
352 ),
353 SCHED_BATCH => (
354 SchedulingPolicy::Batch,
355 NormalPriority::from_binder(priority_or_nice as i8)?,
356 RealtimePriority::NON_REAL_TIME,
357 ),
358 SCHED_FIFO => (
359 SchedulingPolicy::Fifo,
360 NormalPriority::default(),
361 SchedulingPolicy::Fifo.realtime_priority_from(priority_or_nice as i32)?,
362 ),
363 SCHED_RR => (
364 SchedulingPolicy::RoundRobin,
365 NormalPriority::default(),
366 SchedulingPolicy::RoundRobin.realtime_priority_from(priority_or_nice as i32)?,
367 ),
368 _ => return error!(EINVAL),
369 };
370 Ok(Self { policy, normal_priority, realtime_priority, reset_on_fork: false })
371 }
372
373 pub fn fork(self) -> Self {
374 if self.reset_on_fork {
375 let (policy, normal_priority, realtime_priority) = if self.is_realtime() {
376 (
382 SchedulingPolicy::Normal,
383 NormalPriority::default(),
384 RealtimePriority::NON_REAL_TIME,
385 )
386 } else {
387 (
392 self.policy,
393 std::cmp::min(self.normal_priority, NormalPriority::default()),
394 RealtimePriority::NON_REAL_TIME,
395 )
396 };
397 Self {
398 policy,
399 normal_priority,
400 realtime_priority,
401 reset_on_fork: false,
403 }
404 } else {
405 self
406 }
407 }
408
409 pub fn policy_for_sched_getscheduler(&self) -> u32 {
415 let mut base = match self.policy {
416 SchedulingPolicy::Normal => SCHED_NORMAL,
417 SchedulingPolicy::Batch => SCHED_BATCH,
418 SchedulingPolicy::Idle => SCHED_IDLE,
419 SchedulingPolicy::Fifo => SCHED_FIFO,
420 SchedulingPolicy::RoundRobin => SCHED_RR,
421 };
422 if self.reset_on_fork {
423 base |= SCHED_RESET_ON_FORK;
424 }
425 base
426 }
427
428 pub fn get_sched_param(&self) -> sched_param {
433 sched_param {
434 sched_priority: (if self.is_realtime() {
435 self.realtime_priority.value
436 } else {
437 RealtimePriority::NON_REAL_TIME_VALUE
438 }) as i32,
439 }
440 }
441
442 pub fn normal_priority(&self) -> NormalPriority {
443 self.normal_priority
444 }
445
446 pub fn is_realtime(&self) -> bool {
447 match self.policy {
448 SchedulingPolicy::Normal | SchedulingPolicy::Batch | SchedulingPolicy::Idle => false,
449 SchedulingPolicy::Fifo | SchedulingPolicy::RoundRobin => true,
450 }
451 }
452
453 fn role_name(&self) -> &'static str {
466 match self.policy {
467 SchedulingPolicy::Idle => FAIR_PRIORITY_ROLE_NAMES[0],
470
471 SchedulingPolicy::Normal => {
474 FAIR_PRIORITY_ROLE_NAMES[(self.normal_priority.value as usize / 2) + 6]
475 }
476 SchedulingPolicy::Batch => {
477 track_stub!(TODO("https://fxbug.dev/308055542"), "SCHED_BATCH hinting");
478 FAIR_PRIORITY_ROLE_NAMES[(self.normal_priority.value as usize / 2) + 6]
479 }
480
481 SchedulingPolicy::Fifo | SchedulingPolicy::RoundRobin => REALTIME_ROLE_NAME,
487 }
488 }
489
490 pub fn is_less_than_for_binder(&self, other: Self) -> bool {
493 match self.policy {
494 SchedulingPolicy::Fifo | SchedulingPolicy::RoundRobin => match other.policy {
495 SchedulingPolicy::Fifo | SchedulingPolicy::RoundRobin => {
496 self.realtime_priority < other.realtime_priority
497 }
498 SchedulingPolicy::Normal | SchedulingPolicy::Batch | SchedulingPolicy::Idle => {
499 false
500 }
501 },
502 SchedulingPolicy::Normal => match other.policy {
503 SchedulingPolicy::Fifo | SchedulingPolicy::RoundRobin => true,
504 SchedulingPolicy::Normal => {
505 self.normal_priority.value < other.normal_priority.value
506 }
507 SchedulingPolicy::Batch | SchedulingPolicy::Idle => false,
508 },
509 SchedulingPolicy::Batch => match other.policy {
510 SchedulingPolicy::Fifo
511 | SchedulingPolicy::RoundRobin
512 | SchedulingPolicy::Normal => true,
513 SchedulingPolicy::Batch => self.normal_priority.value < other.normal_priority.value,
514 SchedulingPolicy::Idle => false,
515 },
516 SchedulingPolicy::Idle => match other.policy {
518 SchedulingPolicy::Fifo
519 | SchedulingPolicy::RoundRobin
520 | SchedulingPolicy::Normal
521 | SchedulingPolicy::Batch => true,
522 SchedulingPolicy::Idle => false,
523 },
524 }
525 }
526}
527
528impl std::default::Default for SchedulerState {
529 fn default() -> Self {
530 Self {
531 policy: SchedulingPolicy::Normal,
532 normal_priority: NormalPriority::default(),
533 realtime_priority: RealtimePriority::NON_REAL_TIME,
534 reset_on_fork: false,
535 }
536 }
537}
538
539pub fn min_priority_for_sched_policy(policy: u32) -> Result<u8, Errno> {
540 Ok(match policy {
541 SCHED_DEADLINE => RealtimePriority::NON_REAL_TIME_VALUE,
542 _ => SchedulingPolicy::try_from(policy)?.realtime_priority_min(),
543 })
544}
545
546pub fn max_priority_for_sched_policy(policy: u32) -> Result<u8, Errno> {
547 Ok(match policy {
548 SCHED_DEADLINE => RealtimePriority::NON_REAL_TIME_VALUE,
549 _ => SchedulingPolicy::try_from(policy)?.realtime_priority_max(),
550 })
551}
552
553const FAIR_PRIORITY_ROLE_NAMES: [&str; 32] = [
557 "fuchsia.starnix.fair.0",
558 "fuchsia.starnix.fair.1",
559 "fuchsia.starnix.fair.2",
560 "fuchsia.starnix.fair.3",
561 "fuchsia.starnix.fair.4",
562 "fuchsia.starnix.fair.5",
563 "fuchsia.starnix.fair.6",
564 "fuchsia.starnix.fair.7",
565 "fuchsia.starnix.fair.8",
566 "fuchsia.starnix.fair.9",
567 "fuchsia.starnix.fair.10",
568 "fuchsia.starnix.fair.11",
569 "fuchsia.starnix.fair.12",
570 "fuchsia.starnix.fair.13",
571 "fuchsia.starnix.fair.14",
572 "fuchsia.starnix.fair.15",
573 "fuchsia.starnix.fair.16",
574 "fuchsia.starnix.fair.17",
575 "fuchsia.starnix.fair.18",
576 "fuchsia.starnix.fair.19",
577 "fuchsia.starnix.fair.20",
578 "fuchsia.starnix.fair.21",
579 "fuchsia.starnix.fair.22",
580 "fuchsia.starnix.fair.23",
581 "fuchsia.starnix.fair.24",
582 "fuchsia.starnix.fair.25",
583 "fuchsia.starnix.fair.26",
584 "fuchsia.starnix.fair.27",
585 "fuchsia.starnix.fair.28",
586 "fuchsia.starnix.fair.29",
587 "fuchsia.starnix.fair.30",
588 "fuchsia.starnix.fair.31",
589];
590const REALTIME_ROLE_NAME: &str = "fuchsia.starnix.realtime";
591#[cfg(test)]
594mod tests {
595 use super::*;
596 use assert_matches::assert_matches;
597
598 #[fuchsia::test]
599 fn default_role_name() {
600 assert_eq!(SchedulerState::default().role_name(), "fuchsia.starnix.fair.16");
601 }
602
603 #[fuchsia::test]
604 fn normal_with_non_default_nice_role_name() {
605 assert_eq!(
606 SchedulerState {
607 policy: SchedulingPolicy::Normal,
608 normal_priority: NormalPriority { value: 10 },
609 realtime_priority: RealtimePriority::NON_REAL_TIME,
610 reset_on_fork: false
611 }
612 .role_name(),
613 "fuchsia.starnix.fair.11"
614 );
615 assert_eq!(
616 SchedulerState {
617 policy: SchedulingPolicy::Normal,
618 normal_priority: NormalPriority { value: 27 },
619 realtime_priority: RealtimePriority::NON_REAL_TIME,
620 reset_on_fork: false
621 }
622 .role_name(),
623 "fuchsia.starnix.fair.19"
624 );
625 }
626
627 #[fuchsia::test]
628 fn fifo_role_name() {
629 assert_eq!(
630 SchedulerState {
631 policy: SchedulingPolicy::Fifo,
632 normal_priority: NormalPriority::default(),
633 realtime_priority: RealtimePriority { value: 1 },
634 reset_on_fork: false
635 }
636 .role_name(),
637 "fuchsia.starnix.realtime",
638 );
639 assert_eq!(
640 SchedulerState {
641 policy: SchedulingPolicy::Fifo,
642 normal_priority: NormalPriority::default(),
643 realtime_priority: RealtimePriority { value: 2 },
644 reset_on_fork: false
645 }
646 .role_name(),
647 "fuchsia.starnix.realtime",
648 );
649 assert_eq!(
650 SchedulerState {
651 policy: SchedulingPolicy::Fifo,
652 normal_priority: NormalPriority::default(),
653 realtime_priority: RealtimePriority { value: 99 },
654 reset_on_fork: false
655 }
656 .role_name(),
657 "fuchsia.starnix.realtime",
658 );
659 }
660
661 #[fuchsia::test]
662 fn idle_role_name() {
663 assert_eq!(
664 SchedulerState {
665 policy: SchedulingPolicy::Idle,
666 normal_priority: NormalPriority { value: 1 },
667 realtime_priority: RealtimePriority::NON_REAL_TIME,
668 reset_on_fork: false,
669 }
670 .role_name(),
671 "fuchsia.starnix.fair.0"
672 );
673 assert_eq!(
674 SchedulerState {
675 policy: SchedulingPolicy::Idle,
676 normal_priority: NormalPriority::default(),
677 realtime_priority: RealtimePriority::NON_REAL_TIME,
678 reset_on_fork: false,
679 }
680 .role_name(),
681 "fuchsia.starnix.fair.0"
682 );
683 assert_eq!(
684 SchedulerState {
685 policy: SchedulingPolicy::Idle,
686 normal_priority: NormalPriority { value: 40 },
687 realtime_priority: RealtimePriority::NON_REAL_TIME,
688 reset_on_fork: false,
689 }
690 .role_name(),
691 "fuchsia.starnix.fair.0"
692 );
693 }
694
695 #[fuchsia::test]
696 fn build_policy_from_binder() {
697 assert_matches!(SchedulerState::from_binder(SCHED_NORMAL as u8, 0), Ok(_));
698 assert_matches!(
699 SchedulerState::from_binder(SCHED_NORMAL as u8, ((-21) as i8) as u8),
700 Err(_)
701 );
702 assert_matches!(
703 SchedulerState::from_binder(SCHED_NORMAL as u8, ((-20) as i8) as u8),
704 Ok(SchedulerState {
705 policy: SchedulingPolicy::Normal,
706 normal_priority: NormalPriority { value: 40 },
707 realtime_priority: RealtimePriority::NON_REAL_TIME,
708 reset_on_fork: false,
709 })
710 );
711 assert_matches!(SchedulerState::from_binder(SCHED_NORMAL as u8, 1), Ok(_));
712 assert_matches!(SchedulerState::from_binder(SCHED_NORMAL as u8, 19), Ok(_));
713 assert_matches!(SchedulerState::from_binder(SCHED_NORMAL as u8, 20), Err(_));
714 assert_matches!(SchedulerState::from_binder(SCHED_FIFO as u8, 0), Err(_));
715 assert_matches!(SchedulerState::from_binder(SCHED_FIFO as u8, 1), Ok(_));
716 assert_matches!(SchedulerState::from_binder(SCHED_FIFO as u8, 99), Ok(_));
717 assert_matches!(SchedulerState::from_binder(SCHED_FIFO as u8, 100), Err(_));
718 assert_matches!(SchedulerState::from_binder(SCHED_RR as u8, 0), Err(_));
719 assert_matches!(SchedulerState::from_binder(SCHED_RR as u8, 1), Ok(_));
720 assert_matches!(SchedulerState::from_binder(SCHED_RR as u8, 99), Ok(_));
721 assert_matches!(SchedulerState::from_binder(SCHED_RR as u8, 100), Err(_));
722 assert_matches!(SchedulerState::from_binder(SCHED_BATCH as u8, 11), Ok(_));
723 assert_eq!(SchedulerState::from_binder(SCHED_IDLE as u8, 11), error!(EINVAL));
724 assert_matches!(SchedulerState::from_binder(42, 0), Err(_));
725 assert_matches!(SchedulerState::from_binder(42, 0), Err(_));
726 }
727
728 #[fuchsia::test]
731 fn is_less_than_for_binder() {
732 let rr_50 = SchedulerState {
733 policy: SchedulingPolicy::RoundRobin,
734 normal_priority: NormalPriority { value: 1 },
735 realtime_priority: RealtimePriority { value: 50 },
736 reset_on_fork: false,
737 };
738 let rr_40 = SchedulerState {
739 policy: SchedulingPolicy::RoundRobin,
740 normal_priority: NormalPriority { value: 1 },
741 realtime_priority: RealtimePriority { value: 40 },
742 reset_on_fork: false,
743 };
744 let fifo_50 = SchedulerState {
745 policy: SchedulingPolicy::Fifo,
746 normal_priority: NormalPriority { value: 1 },
747 realtime_priority: RealtimePriority { value: 50 },
748 reset_on_fork: false,
749 };
750 let fifo_40 = SchedulerState {
751 policy: SchedulingPolicy::Fifo,
752 normal_priority: NormalPriority { value: 1 },
753 realtime_priority: RealtimePriority { value: 40 },
754 reset_on_fork: false,
755 };
756 let normal_40 = SchedulerState {
757 policy: SchedulingPolicy::Normal,
758 normal_priority: NormalPriority { value: 40 },
759 realtime_priority: RealtimePriority::NON_REAL_TIME,
760 reset_on_fork: true,
761 };
762 let normal_10 = SchedulerState {
763 policy: SchedulingPolicy::Normal,
764 normal_priority: NormalPriority { value: 10 },
765 realtime_priority: RealtimePriority::NON_REAL_TIME,
766 reset_on_fork: true,
767 };
768 let batch_40 = SchedulerState {
769 policy: SchedulingPolicy::Batch,
770 normal_priority: NormalPriority { value: 40 },
771 realtime_priority: RealtimePriority::NON_REAL_TIME,
772 reset_on_fork: true,
773 };
774 let batch_30 = SchedulerState {
775 policy: SchedulingPolicy::Batch,
776 normal_priority: NormalPriority { value: 30 },
777 realtime_priority: RealtimePriority::NON_REAL_TIME,
778 reset_on_fork: true,
779 };
780 let idle_40 = SchedulerState {
781 policy: SchedulingPolicy::Idle,
782 normal_priority: NormalPriority { value: 40 },
783 realtime_priority: RealtimePriority::NON_REAL_TIME,
784 reset_on_fork: true,
785 };
786 let idle_30 = SchedulerState {
787 policy: SchedulingPolicy::Idle,
788 normal_priority: NormalPriority { value: 30 },
789 realtime_priority: RealtimePriority::NON_REAL_TIME,
790 reset_on_fork: true,
791 };
792 assert!(!fifo_50.is_less_than_for_binder(fifo_50));
793 assert!(!rr_50.is_less_than_for_binder(rr_50));
794 assert!(!fifo_50.is_less_than_for_binder(rr_50));
795 assert!(!rr_50.is_less_than_for_binder(fifo_50));
796 assert!(!fifo_50.is_less_than_for_binder(rr_40));
797 assert!(rr_40.is_less_than_for_binder(fifo_50));
798 assert!(!rr_50.is_less_than_for_binder(fifo_40));
799 assert!(fifo_40.is_less_than_for_binder(rr_50));
800 assert!(!fifo_40.is_less_than_for_binder(normal_40));
801 assert!(normal_40.is_less_than_for_binder(fifo_40));
802 assert!(!rr_40.is_less_than_for_binder(normal_40));
803 assert!(normal_40.is_less_than_for_binder(rr_40));
804 assert!(!normal_40.is_less_than_for_binder(normal_40));
805 assert!(!normal_40.is_less_than_for_binder(normal_10));
806 assert!(normal_10.is_less_than_for_binder(normal_40));
807 assert!(!normal_10.is_less_than_for_binder(batch_40));
808 assert!(batch_40.is_less_than_for_binder(normal_10));
809 assert!(!batch_40.is_less_than_for_binder(batch_40));
810 assert!(!batch_40.is_less_than_for_binder(batch_30));
811 assert!(batch_30.is_less_than_for_binder(batch_40));
812 assert!(!batch_30.is_less_than_for_binder(idle_40));
813 assert!(idle_40.is_less_than_for_binder(batch_30));
814 assert!(!idle_40.is_less_than_for_binder(idle_40));
815 assert!(!idle_40.is_less_than_for_binder(idle_30));
816 assert!(!idle_30.is_less_than_for_binder(idle_40));
817 }
818
819 #[fuchsia::test]
820 async fn role_overrides_non_realtime() {
821 crate::testing::spawn_kernel_and_run_sync(|_locked, current_task| {
822 let mut builder = RoleOverrides::new();
823 builder.add("my_task", "my_task", "overridden_role");
824 let overrides = builder.build().unwrap();
825 let manager = SchedulerManager {
826 role_manager: None,
827 role_overrides: overrides,
828 profile_handle_cache: Mutex::new(HashMap::new()),
829 };
830
831 current_task.set_command_name(starnix_task_command::TaskCommand::new(b"my_task"));
832
833 let mut state = SchedulerState::default();
834 state.policy = SchedulingPolicy::Normal;
835
836 let role = manager.role_name_inner(current_task, state).expect("role_name");
837 assert_eq!(role, "overridden_role");
838 })
839 .await;
840 }
841}