use std::io;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SchedulerProfile {
Default,
RealtimeFifo {
priority: u8,
},
RealtimeRoundRobin {
priority: u8,
},
Deadline {
runtime_ns: u64,
deadline_ns: u64,
period_ns: u64,
},
}
impl SchedulerProfile {
pub fn apply_to_current_thread(&self) -> io::Result<()> {
#[cfg(target_os = "linux")]
{
crate::syscalls::apply_scheduler(self)
}
#[cfg(not(target_os = "linux"))]
{
let _ = self;
Err(io::Error::new(
io::ErrorKind::Unsupported,
"SchedulerProfile::apply_to_current_thread requires Linux",
))
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct RunningSchedulerInfo {
pub kind: SchedulerKind,
pub priority: u8,
pub runtime_ns: u64,
pub deadline_ns: u64,
pub period_ns: u64,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SchedulerKind {
Other,
Fifo,
RoundRobin,
Deadline,
}
pub fn current_scheduler() -> io::Result<RunningSchedulerInfo> {
#[cfg(target_os = "linux")]
{
crate::syscalls::read_scheduler()
}
#[cfg(not(target_os = "linux"))]
{
Err(io::Error::new(
io::ErrorKind::Unsupported,
"current_scheduler() requires Linux",
))
}
}
#[cfg(test)]
#[allow(clippy::expect_used, clippy::unwrap_used, clippy::panic)]
mod tests {
use super::*;
#[test]
fn profile_is_send_sync_clone_eq() {
fn assert_traits<T: Send + Sync + Clone + Copy + PartialEq>() {}
assert_traits::<SchedulerProfile>();
assert_traits::<RunningSchedulerInfo>();
assert_traits::<SchedulerKind>();
}
#[test]
fn profile_default_is_distinct_from_fifo() {
assert_ne!(
SchedulerProfile::Default,
SchedulerProfile::RealtimeFifo { priority: 1 }
);
}
#[test]
#[cfg(not(target_os = "linux"))]
fn apply_returns_unsupported_off_linux() {
let err = SchedulerProfile::Default
.apply_to_current_thread()
.unwrap_err();
assert_eq!(err.kind(), io::ErrorKind::Unsupported);
}
#[test]
#[cfg(not(target_os = "linux"))]
fn current_scheduler_returns_unsupported_off_linux() {
let err = current_scheduler().unwrap_err();
assert_eq!(err.kind(), io::ErrorKind::Unsupported);
}
#[test]
#[cfg(target_os = "linux")]
fn linux_default_apply_round_trips_via_getattr() {
SchedulerProfile::Default
.apply_to_current_thread()
.expect("apply default");
let info = current_scheduler().expect("read");
assert_eq!(info.kind, SchedulerKind::Other);
}
#[test]
#[cfg(target_os = "linux")]
fn linux_eperm_for_deadline_without_caps() {
let res = SchedulerProfile::Deadline {
runtime_ns: 1_000_000,
deadline_ns: 5_000_000,
period_ns: 10_000_000,
}
.apply_to_current_thread();
if let Err(e) = res {
assert!(matches!(
e.kind(),
io::ErrorKind::PermissionDenied
| io::ErrorKind::InvalidInput
| io::ErrorKind::ResourceBusy
| io::ErrorKind::Other,
));
}
}
}