extern crate libc;
#[derive(Debug, Copy, Clone)]
pub enum Error {
Priority(&'static str),
Pthread(i32),
Ffi(&'static str),
}
pub use libc::sched_param as ScheduleParams;
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
pub enum RealtimeThreadSchedulePolicy {
Fifo,
RoundRobin,
}
impl RealtimeThreadSchedulePolicy {
fn to_posix(&self) -> libc::c_int {
match *self {
RealtimeThreadSchedulePolicy::Fifo => 1,
RealtimeThreadSchedulePolicy::RoundRobin => 2,
}
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
pub enum NormalThreadSchedulePolicy {
Idle,
Batch,
Other,
Normal,
}
impl NormalThreadSchedulePolicy {
fn to_posix(&self) -> libc::c_int {
match *self {
NormalThreadSchedulePolicy::Idle => 5,
NormalThreadSchedulePolicy::Batch => 3,
NormalThreadSchedulePolicy::Other | NormalThreadSchedulePolicy::Normal => 0,
}
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
pub enum ThreadSchedulePolicy {
Normal(NormalThreadSchedulePolicy),
Realtime(RealtimeThreadSchedulePolicy),
}
impl ThreadSchedulePolicy {
fn to_posix(&self) -> libc::c_int {
match *self {
ThreadSchedulePolicy::Normal(p) => p.to_posix(),
ThreadSchedulePolicy::Realtime(p) => p.to_posix(),
}
}
fn from_posix(policy: libc::c_int) -> Result<ThreadSchedulePolicy, Error> {
match policy {
0 => Ok(ThreadSchedulePolicy::Normal(NormalThreadSchedulePolicy::Normal)),
3 => Ok(ThreadSchedulePolicy::Normal(NormalThreadSchedulePolicy::Batch)),
5 => Ok(ThreadSchedulePolicy::Normal(NormalThreadSchedulePolicy::Idle)),
1 => Ok(ThreadSchedulePolicy::Realtime(RealtimeThreadSchedulePolicy::Fifo)),
2 => Ok(ThreadSchedulePolicy::Realtime(RealtimeThreadSchedulePolicy::RoundRobin)),
_ => Err(Error::Ffi("Can't parse schedule policy from posix")),
}
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
pub enum ThreadPriority {
Min,
Specific(u8),
Max,
}
impl ThreadPriority {
fn to_posix(&self, policy: ThreadSchedulePolicy) -> Result<libc::c_int, Error> {
let ret = match *self {
ThreadPriority::Min => {
match policy {
ThreadSchedulePolicy::Realtime(_) => Ok(1),
_ => Ok(0)
}
},
ThreadPriority::Specific(p) => {
match policy {
ThreadSchedulePolicy::Realtime(_) if (p == 0 || p > 99) => {
Err(Error::Priority("The value is out of range [0; 99]"))
},
ThreadSchedulePolicy::Normal(_) if p != 0 => {
Err(Error::Priority("The value can be only 0 for normal scheduling policy"))
},
_ => Ok(p)
}
},
ThreadPriority::Max => {
match policy {
ThreadSchedulePolicy::Realtime(_) => Ok(99),
_ => Ok(0),
}
},
};
ret.map(|p| p as libc::c_int)
}
}
pub fn set_thread_priority(native: libc::pthread_t,
priority: ThreadPriority,
policy: ThreadSchedulePolicy) -> Result<(), Error> {
unsafe {
match libc::pthread_setschedprio(native, priority.to_posix(policy)?) {
0 => Ok(()),
e => Err(Error::Pthread(e)),
}
}
}
pub fn thread_native_id() -> libc::pthread_t {
unsafe {
libc::pthread_self()
}
}
pub fn thread_schedule_policy() -> Result<ThreadSchedulePolicy, Error> {
unsafe {
ThreadSchedulePolicy::from_posix(libc::sched_getscheduler(libc::getpid()))
}
}
pub fn set_thread_schedule_policy(native: libc::pthread_t,
policy: ThreadSchedulePolicy,
params: ScheduleParams) -> Result<(), Error> {
unsafe {
let ret = libc::pthread_setschedparam(native,
policy.to_posix(),
¶ms as *const ScheduleParams);
match ret {
0 => Ok(()),
e => Err(Error::Pthread(e)),
}
}
}
pub fn thread_schedule_policy_param(native: libc::pthread_t) -> Result<(ThreadSchedulePolicy,
ScheduleParams), Error> {
unsafe {
let mut policy = 0 as libc::c_int;
let mut params = ScheduleParams { sched_priority: 0 };
let ret = libc::pthread_getschedparam(native,
&mut policy as *mut libc::c_int,
&mut params as *mut ScheduleParams);
match ret {
0 => Ok((ThreadSchedulePolicy::from_posix(policy)?, params)),
e => Err(Error::Pthread(e)),
}
}
}
#[cfg(test)]
mod tests {
use ::*;
#[test]
fn thread_schedule_policy_param_test() {
let thread_id = thread_native_id();
assert!(thread_schedule_policy_param(thread_id).is_ok());
}
#[test]
fn set_thread_priority_test() {
let thread_id = thread_native_id();
assert!(set_thread_priority(thread_id,
ThreadPriority::Min,
ThreadSchedulePolicy::Normal(NormalThreadSchedulePolicy::Normal)).is_ok());
assert!(set_thread_priority(thread_id,
ThreadPriority::Max,
ThreadSchedulePolicy::Normal(NormalThreadSchedulePolicy::Normal)).is_ok());
assert!(set_thread_priority(thread_id,
ThreadPriority::Specific(0),
ThreadSchedulePolicy::Normal(NormalThreadSchedulePolicy::Normal)).is_ok());
}
}