use crate::PriorityCaps;
const NICE_LADDER: [i32; 7] = [19, 10, 5, 0, -5, -10, -20];
pub(crate) fn priority_capabilities() -> PriorityCaps {
let nice_floor = nice_floor_from_rlimit();
#[cfg(feature = "rtkit")]
let rtkit_min_nice = crate::platform::linux::rtkit::Broker::rtkit()
.ok()
.map(|mut broker| broker.min_nice_level().clamp(-20, 0) as i32);
#[cfg(not(feature = "rtkit"))]
let rtkit_min_nice: Option<i32> = None;
PriorityCaps {
effective_rank: effective_ranks(nice_floor, rtkit_min_nice),
}
}
fn nice_floor_from_rlimit() -> i32 {
let mut limit = libc::rlimit {
rlim_cur: 0,
rlim_max: 0,
};
if unsafe { libc::getrlimit(libc::RLIMIT_NICE, &mut limit) } != 0 {
return 20; }
let cur = limit.rlim_cur.min(40) as i32;
20 - cur
}
fn effective_ranks(nice_floor: i32, rtkit_min_nice: Option<i32>) -> [u8; 7] {
let effective = NICE_LADDER.map(|nice| effective_nice(nice, nice_floor, rtkit_min_nice));
let mut distinct: Vec<i32> = effective.to_vec();
distinct.sort_unstable_by(|a, b| b.cmp(a));
distinct.dedup();
effective.map(|nice| distinct.iter().position(|&v| v == nice).unwrap() as u8)
}
fn effective_nice(nice: i32, nice_floor: i32, rtkit_min_nice: Option<i32>) -> i32 {
if nice >= 0 || nice >= nice_floor {
nice
} else if let Some(min_nice) = rtkit_min_nice {
nice.max(min_nice)
} else {
0
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn unprivileged_no_rtkit_collapses_the_top() {
let ranks = effective_ranks(20, None);
assert_eq!(ranks, [0, 1, 2, 3, 3, 3, 3]);
}
#[test]
fn unprivileged_with_rtkit_keeps_seven_distinct() {
let ranks = effective_ranks(20, Some(-15));
assert_eq!(ranks, [0, 1, 2, 3, 4, 5, 6]);
}
#[test]
fn privileged_full_ladder() {
let ranks = effective_ranks(-20, None);
assert_eq!(ranks, [0, 1, 2, 3, 4, 5, 6]);
}
#[test]
fn partial_rlimit_collapses_only_what_it_must() {
let ranks = effective_ranks(-10, None);
assert_eq!(ranks, [0, 1, 2, 3, 4, 5, 3]);
let caps = PriorityCaps {
effective_rank: ranks,
};
assert!(!caps.distinct(
crate::ThreadPriority::Normal,
crate::ThreadPriority::TimeCritical
));
assert!(caps.distinct(
crate::ThreadPriority::Normal,
crate::ThreadPriority::Highest
));
}
}