Refine the implementation of NiceValue

This commit is contained in:
LI Qing 2024-03-12 10:48:46 +08:00 committed by volcano
parent db3a31d42e
commit f9839299b2
5 changed files with 53 additions and 54 deletions

@ -36,8 +36,9 @@ impl ProcINode for ProcStatINode {
let stime = 0; let stime = 0;
let cutime = 0; let cutime = 0;
let cstime = 0; let cstime = 0;
let priority = main_thread.nice().read().unwrap().to_priority_val(); // Convert [19,-20] to [39,0].
let nice = main_thread.nice().read().unwrap().raw_val(); let priority = main_thread.nice().read().unwrap().to_raw_val() + 20;
let nice = main_thread.nice().read().unwrap().to_raw_val();
let num_threads = self.0.threads().len(); let num_threads = self.0.threads().len();
let itrealvalue = 0; let itrealvalue = 0;
let starttime = self.0.start_time(); let starttime = self.0.start_time();

@ -42,6 +42,9 @@ pub struct Thread {
fs: FsViewRef, fs: FsViewRef,
files: FileTableRef, files: FileTableRef,
sched: SchedAgentRef, sched: SchedAgentRef,
// According to POSIX, the nice value is a per-process setting.
// In our implementation, the threads belong to same process
// share the same nice value.
nice: NiceValueRef, nice: NiceValueRef,
rlimits: ResourceLimitsRef, rlimits: ResourceLimitsRef,
// Signal // Signal

@ -2,18 +2,17 @@ use super::priority::{NiceValue, PrioWhich};
use crate::prelude::*; use crate::prelude::*;
use crate::process::table::{get_all_processes, get_pgrp, get_process}; use crate::process::table::{get_all_processes, get_pgrp, get_process};
pub fn do_set_priority(which: PrioWhich, who: i32, prio: NiceValue) -> Result<()> { pub fn do_set_priority(which: PrioWhich, who: i32, nice: NiceValue) -> Result<()> {
debug!( debug!(
"set_priority: which: {:?}, who: {}, prio: {:?}", "set_priority: which: {:?}, who: {}, nice: {:?}",
which, who, prio which, who, nice
); );
let processes = get_processes(which, who)?; let processes = get_processes(which, who)?;
for process in processes.iter() { for process in processes.iter() {
let main_thread = process for thread in process.threads().iter() {
.main_thread() *thread.nice().write().unwrap() = nice;
.ok_or_else(|| errno!(ESRCH, "invalid pid"))?; }
*main_thread.nice().write().unwrap() = prio;
} }
Ok(()) Ok(())
} }
@ -22,27 +21,25 @@ pub fn do_get_priority(which: PrioWhich, who: i32) -> Result<NiceValue> {
debug!("get_priority: which: {:?}, who: {}", which, who); debug!("get_priority: which: {:?}, who: {}", which, who);
let processes = get_processes(which, who)?; let processes = get_processes(which, who)?;
let prio = { let nice = {
let mut prio = NiceValue::max_value(); let mut nice = NiceValue::MAX;
for process in processes.iter() { for process in processes.iter() {
let main_thread = process let main_thread = process
.main_thread() .main_thread()
.ok_or_else(|| errno!(ESRCH, "invalid pid"))?; .ok_or_else(|| errno!(ESRCH, "invalid pid"))?;
let nice_value = main_thread.nice().read().unwrap(); let current_nice = main_thread.nice().read().unwrap();
// Returns the highest priority enjoyed by the processes // Returns the highest priority enjoyed by the processes
if *nice_value < prio { if *current_nice < nice {
prio = *nice_value; nice = *current_nice;
} }
} }
prio nice
}; };
Ok(prio) Ok(nice)
} }
// According to POSIX, the nice value is a per-process setting.
// In our implementation, the threads belong to same process share the same nice value.
fn get_processes(which: PrioWhich, who: i32) -> Result<Vec<crate::process::ProcessRef>> { fn get_processes(which: PrioWhich, who: i32) -> Result<Vec<crate::process::ProcessRef>> {
Ok(match which { let processes = match which {
PrioWhich::PRIO_PROCESS => { PrioWhich::PRIO_PROCESS => {
let process = if who == 0 { let process = if who == 0 {
current!().process().clone() current!().process().clone()
@ -67,5 +64,10 @@ fn get_processes(which: PrioWhich, who: i32) -> Result<Vec<crate::process::Proce
return_errno!(ESRCH, "no such user"); return_errno!(ESRCH, "no such user");
} }
} }
}) };
if processes.is_empty() {
return_errno!(ESRCH, "no such process");
}
Ok(processes)
} }

@ -21,55 +21,48 @@ impl TryFrom<i32> for PrioWhich {
} }
} }
/// Process priority value /// Process scheduling nice value.
/// ///
/// Lower values give a process a higher scheduling priority. /// Lower values give a process a higher scheduling priority.
#[derive(Copy, Clone, Debug, Default, PartialEq, PartialOrd)] #[derive(Copy, Clone, Debug, Default, PartialEq, PartialOrd)]
pub struct NiceValue { pub struct NiceValue {
value: i32, value: i8,
} }
impl NiceValue { impl NiceValue {
const MAX_PRIO: i32 = 19; pub const MAX: Self = Self { value: 19 };
const MIN_PRIO: i32 = -20; pub const MIN: Self = Self { value: -20 };
pub fn max_value() -> Self { /// Create a nice value from a raw value.
Self { ///
value: Self::MAX_PRIO, /// The raw value given beyond the range are automatically adjusted
/// to the nearest boundary value.
pub fn new(raw: i8) -> Self {
if raw < Self::MIN.value {
Self::MIN
} else if raw > Self::MAX.value {
Self::MAX
} else {
Self { value: raw }
} }
} }
pub fn min_value() -> Self { /// Convert to the raw value with range [19, -20].
Self { pub fn to_raw_val(self) -> i8 {
value: Self::MIN_PRIO,
}
}
pub fn raw_val(&self) -> i32 {
self.value self.value
} }
/// Convert [19,-20] to priority value [39,0].
pub fn to_priority_val(&self) -> i32 {
self.value - Self::MIN_PRIO
}
/// Convert [19,-20] to rlimit style value [1,40].
pub fn to_rlimit_val(&self) -> i32 {
Self::MAX_PRIO - self.value + 1
}
} }
impl From<i32> for NiceValue { impl From<i32> for NiceValue {
fn from(raw: i32) -> Self { fn from(raw: i32) -> Self {
let value = if raw < Self::MIN_PRIO { let adj_raw = if raw > i8::MAX as i32 {
Self::MIN_PRIO i8::MAX
} else if raw > Self::MAX_PRIO { } else if raw < i8::MIN as i32 {
Self::MAX_PRIO i8::MIN
} else { } else {
raw raw as i8
}; };
Self { value } Self::new(adj_raw)
} }
} }

@ -83,16 +83,16 @@ pub fn do_getcpu(cpu_ptr: *mut u32, node_ptr: *mut u32) -> Result<isize> {
pub fn do_set_priority(which: i32, who: i32, prio: i32) -> Result<isize> { pub fn do_set_priority(which: i32, who: i32, prio: i32) -> Result<isize> {
let which = PrioWhich::try_from(which)?; let which = PrioWhich::try_from(which)?;
let prio = NiceValue::from(prio); let nice = NiceValue::from(prio);
super::do_priority::do_set_priority(which, who, prio)?; super::do_priority::do_set_priority(which, who, nice)?;
Ok(0) Ok(0)
} }
pub fn do_get_priority(which: i32, who: i32) -> Result<isize> { pub fn do_get_priority(which: i32, who: i32) -> Result<isize> {
let which = PrioWhich::try_from(which)?; let which = PrioWhich::try_from(which)?;
let prio = super::do_priority::do_get_priority(which, who)?; let nice = super::do_priority::do_get_priority(which, who)?;
// To avoid negative return values, "getpriority()" will // To avoid negative return values, "getpriority()" will
// not return the normal nice-value, but a negated value that // not return the normal nice-value, but a negated value that
// has been offset by 20 (ie it returns 40..1 instead of -20..19) // has been offset by 20 (ie it returns 40..1 instead of -20..19)
Ok(prio.to_rlimit_val() as isize) Ok((20 - nice.to_raw_val()) as _)
} }