use std::path::Path;
use crate::{RobotException, RobotResult};
pub trait RealtimeBehavior<C, H> {
fn enter_realtime(&mut self, realtime_config: C) -> RobotResult<H>;
fn exit_realtime(&mut self) -> RobotResult<()>;
fn quality_of_service(&self) -> f64;
}
pub fn is_hardware_realtime() -> bool {
if cfg!(target_os = "linux") {
Path::new("/sys/kernel/realtime").exists()
} else if cfg!(target_os = "windows") {
true
} else {
println!("Unknown OS, assuming realtime kernel.");
true
}
}
pub fn set_realtime_priority() -> RobotResult<()> {
#[cfg(target_os = "windows")]
{
use winapi::um::{
processthreadsapi::{
GetCurrentProcess, GetCurrentThread, SetPriorityClass, SetThreadPriority,
},
winbase::{REALTIME_PRIORITY_CLASS, THREAD_PRIORITY_TIME_CRITICAL},
};
unsafe {
let process_handle = GetCurrentProcess();
if SetPriorityClass(process_handle, REALTIME_PRIORITY_CLASS) == 0 {
return Err(RobotException::RealtimeException(
"unable to set realtime priority, try run as an adminstrator!".to_string(),
));
}
let thread_handle = GetCurrentThread();
if SetThreadPriority(thread_handle, THREAD_PRIORITY_TIME_CRITICAL as i32) == 0 {
return Err(RobotException::RealtimeException(
"unable to set max thread priority".to_string(),
));
}
}
}
#[cfg(target_os = "linux")]
unsafe {
let max_priority = libc::sched_get_priority_max(libc::SCHED_FIFO);
if max_priority == -1 {
return Err(RobotException::RealtimeException(
"unable to get maximum possible thread priority".to_string(),
));
}
let thread_param = libc::sched_param {
sched_priority: max_priority - 1,
};
if libc::pthread_setschedparam(libc::pthread_self(), libc::SCHED_FIFO, &thread_param) != 0 {
return Err(RobotException::RealtimeException(
"unable to set realtime scheduling".to_string(),
));
}
if libc::mlockall(libc::MCL_CURRENT | libc::MCL_FUTURE) != 0 {
return Err(RobotException::RealtimeException(
"unable to lock memory".to_string(),
));
}
}
Ok(())
}