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