blob: e310b90e8edeb11c83398a7677321ab9de0c8d35 [file] [log] [blame] [edit]
// Copyright 2023 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use crate::types::*;
// In user space, priority (niceness) is an integer from -20..19 (inclusive)
// with the default being 0.
//
// In the kernel it is represented as a range from 1..40 (inclusive).
// The conversion is done by the formula: user_nice = 20 - kernel_nice.
//
// In POSIX, priority is a per-process setting, but in Linux it is per-thread.
// See https://man7.org/linux/man-pages/man2/setpriority.2.html#BUGS and
// https://man7.org/linux/man-pages/man2/setpriority.2.html#NOTES
const DEFAULT_TASK_PRIORITY: u8 = 20;
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum SchedulerPolicy {
Normal {
// 1-40, from setpriority()
priority: u8,
},
Batch {
// 1-40, from setpriority()
priority: u8,
},
Idle {
// 1-40, from setpriority()
priority: u8,
},
Fifo {
/// 0-99, from sched_setpriority()
priority: u32,
},
RoundRobin {
/// 0-99, from sched_setpriority()
priority: u32,
},
}
impl std::default::Default for SchedulerPolicy {
fn default() -> Self {
Self::Normal { priority: DEFAULT_TASK_PRIORITY }
}
}
impl SchedulerPolicy {
pub fn is_default(&self) -> bool {
matches!(self, Self::Normal { priority: DEFAULT_TASK_PRIORITY })
}
pub fn from_raw(policy: u32, params: sched_param, rlimit: u64) -> Result<Self, Errno> {
let valid_priorities =
min_priority_for_sched_policy(policy)?..=max_priority_for_sched_policy(policy)?;
if !valid_priorities.contains(&params.sched_priority) {
return error!(EINVAL);
}
// ok to cast i32->u64, above range excludes negatives
match (policy, params.sched_priority as u64) {
(SCHED_FIFO, priority) => {
Ok(Self::Fifo { priority: std::cmp::min(priority, rlimit) as u32 })
}
(SCHED_RR, priority) => {
Ok(Self::RoundRobin { priority: std::cmp::min(priority, rlimit) as u32 })
}
// Non-real-time scheduler policies are not allowed to set their nice value from
// the sched_priority field.
(SCHED_NORMAL, 0) => Ok(Self::Normal { priority: DEFAULT_TASK_PRIORITY }),
(SCHED_BATCH, 0) => Ok(Self::Batch { priority: DEFAULT_TASK_PRIORITY }),
(SCHED_IDLE, 0) => Ok(Self::Idle { priority: DEFAULT_TASK_PRIORITY }),
_ => error!(EINVAL),
}
}
pub fn raw_policy(&self) -> u32 {
match self {
Self::Normal { .. } => SCHED_NORMAL,
Self::Batch { .. } => SCHED_BATCH,
Self::Idle { .. } => SCHED_IDLE,
Self::Fifo { .. } => SCHED_FIFO,
Self::RoundRobin { .. } => SCHED_RR,
}
}
/// Return the raw "normal priority" for a process, in the range 1-40. This is the value used to
/// compute nice, and does not apply to real-time scheduler policies.
pub fn raw_priority(&self) -> u8 {
match self {
Self::Normal { priority } | Self::Batch { priority } | Self::Idle { priority } => {
*priority
}
_ => DEFAULT_TASK_PRIORITY,
}
}
/// Set the "normal priority" for a process, in the range 1-40. This is the value used to
/// compute nice, and does not apply to real-time scheduler policies.
pub fn set_raw_priority(&mut self, new_priority: u8) {
match self {
Self::Normal { priority } | Self::Batch { priority } | Self::Idle { priority } => {
*priority = new_priority
}
_ => (),
}
}
pub fn raw_params(&self) -> sched_param {
match self {
Self::Normal { .. } | Self::Batch { .. } | Self::Idle { .. } => {
sched_param { sched_priority: 0 }
}
Self::Fifo { priority } | Self::RoundRobin { priority } => {
sched_param { sched_priority: *priority as i32 }
}
}
}
}
pub fn min_priority_for_sched_policy(policy: u32) -> Result<i32, Errno> {
match policy {
SCHED_NORMAL | SCHED_BATCH | SCHED_IDLE | SCHED_DEADLINE => Ok(0),
SCHED_FIFO | SCHED_RR => Ok(1),
_ => error!(EINVAL),
}
}
pub fn max_priority_for_sched_policy(policy: u32) -> Result<i32, Errno> {
match policy {
SCHED_NORMAL | SCHED_BATCH | SCHED_IDLE | SCHED_DEADLINE => Ok(0),
SCHED_FIFO | SCHED_RR => Ok(99),
_ => error!(EINVAL),
}
}