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