#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[derive(Deserialize, Serialize)]
#[serde(deny_unknown_fields)]
pub enum IoPriority
{
Idle,
BestEffort(RealTimeOrBestEffortIoPriorityLevel),
RealTime(RealTimeOrBestEffortIoPriorityLevel),
}
impl Default for IoPriority
{
#[inline(always)]
fn default() -> Self
{
IoPriority::BestEffort(RealTimeOrBestEffortIoPriorityLevel::_4)
}
}
impl TryFrom<u16> for IoPriority
{
type Error = &'static str;
#[inline(always)]
fn try_from(ioprio: u16) -> Result<Self, Self::Error>
{
match Self::parse_ioprio(ioprio)?
{
None => Err("Can not be IOPRIO_CLASS::IOPRIO_CLASS_NONE"),
Some(value) => Ok(value),
}
}
}
impl Into<u16> for IoPriority
{
#[inline(always)]
fn into(self) -> u16
{
use self::IoPriority::*;
use RealTimeOrBestEffortIoPriorityLevel::_0;
let (scheduling_class, scheduling_level) = match self
{
Idle => (IOPRIO_CLASS::IOPRIO_CLASS_IDLE, _0),
BestEffort(priority) => (IOPRIO_CLASS::IOPRIO_CLASS_BE, priority),
RealTime(priority) => (IOPRIO_CLASS::IOPRIO_CLASS_RT, priority),
};
IOPRIO_PRIO_VALUE(scheduling_class as u8 as u16, scheduling_level as u8 as u16)
}
}
impl TryFrom<i32> for IoPriority
{
type Error = &'static str;
#[inline(always)]
fn try_from(ioprio: i32) -> Result<Self, Self::Error>
{
if unlikely!(ioprio < 0)
{
return Err("ioprio can not be negative")
}
match Self::parse_ioprio_result(ioprio)?
{
None => Err("Can not be IOPRIO_CLASS::IOPRIO_CLASS_NONE"),
Some(value) => Ok(value),
}
}
}
impl IoPriority
{
pub fn get_for_process_group(process_group_identifier: ProcessGroupIdentifierChoice) -> Result<Self, bool>
{
Self::get(process_group_identifier, IOPRIO_WHO::IOPRIO_WHO_PGRP)
}
#[inline(always)]
pub fn get_for_process(process_identifier: ProcessIdentifierChoice) -> Result<Self, bool>
{
Self::get(process_identifier, IOPRIO_WHO::IOPRIO_WHO_PROCESS)
}
#[inline(always)]
pub fn get_for_thread(thread_identifier: ThreadIdentifier) -> Result<Self, bool>
{
Self::get(thread_identifier, IOPRIO_WHO::IOPRIO_WHO_PROCESS)
}
#[inline(always)]
pub fn get_for_user(user_identifier: UserIdentifier) -> Result<Self, bool>
{
Self::get(user_identifier, IOPRIO_WHO::IOPRIO_WHO_USER)
}
#[inline(always)]
pub(crate) fn explain_error(error: bool) -> &'static str
{
if error
{
"no such thread"
}
else
{
"permission denied"
}
}
#[inline(always)]
fn get(which: impl Into<i32>, who: IOPRIO_WHO) -> Result<Self, bool>
{
let result = ioprio_get(which.into(), who);
if likely!(result >= 0)
{
Ok(Self::parse_ioprio_result(result).unwrap().expect("Should never be NONE"))
}
else if likely!(result == -1)
{
match errno().0
{
EPERM => Err(true),
ESRCH => Err(false),
EINVAL => panic!("Invalid value for which."),
unexpected @ _ => panic!("Unexpected error from ioprio_get() of {}", unexpected)
}
}
else
{
unreachable_code(format_args!("Unexpected result of {} from ioprio_get()", result))
}
}
#[inline(always)]
pub fn set_for_process_group(self, process_group_identifier: ProcessGroupIdentifierChoice) -> Result<(), bool>
{
self.set(process_group_identifier, IOPRIO_WHO::IOPRIO_WHO_PGRP)
}
#[inline(always)]
pub fn set_for_process(self, process_identifier: ProcessIdentifierChoice) -> Result<(), bool>
{
self.set(process_identifier, IOPRIO_WHO::IOPRIO_WHO_PROCESS)
}
#[inline(always)]
pub fn set_for_thread(self, thread_identifier: ThreadIdentifier) -> Result<(), bool>
{
self.set(thread_identifier, IOPRIO_WHO::IOPRIO_WHO_PROCESS)
}
#[inline(always)]
pub fn set_for_user(self, user_identifier: UserIdentifier) -> Result<(), bool>
{
self.set(user_identifier, IOPRIO_WHO::IOPRIO_WHO_USER)
}
#[inline(always)]
fn set(self, which: impl Into<i32>, who: IOPRIO_WHO) -> Result<(), bool>
{
let value: u16 = self.into();
Self::change(which, who, value)
}
#[inline(always)]
pub fn reset_to_default_for_process_group(process_group_identifier: ProcessGroupIdentifierChoice) -> Result<(), bool>
{
Self::reset_to_default(process_group_identifier, IOPRIO_WHO::IOPRIO_WHO_PGRP)
}
#[inline(always)]
pub fn reset_to_default_for_process(process_identifier: ProcessIdentifierChoice) -> Result<(), bool>
{
Self::reset_to_default(process_identifier, IOPRIO_WHO::IOPRIO_WHO_PROCESS)
}
#[inline(always)]
pub fn reset_to_default_for_thread(thread_identifier: ThreadIdentifier) -> Result<(), bool>
{
Self::reset_to_default(thread_identifier, IOPRIO_WHO::IOPRIO_WHO_PROCESS)
}
#[inline(always)]
pub fn reset_to_default_for_user(user_identifier: UserIdentifier) -> Result<(), bool>
{
Self::reset_to_default(user_identifier, IOPRIO_WHO::IOPRIO_WHO_USER)
}
#[inline(always)]
fn reset_to_default(which: impl Into<i32>, who: IOPRIO_WHO) -> Result<(), bool>
{
Self::change(which, who, 0)
}
#[inline(always)]
fn change(which: impl Into<i32>, who: IOPRIO_WHO, value: u16) -> Result<(), bool>
{
let result = ioprio_set(which.into(), who, value);
if likely!(result == 0)
{
Ok(())
}
else if likely!(result == -1)
{
match errno().0
{
EPERM => Err(true),
ESRCH => Err(false),
EINVAL => panic!("Invalid value for which."),
unexpected @ _ => panic!("Unexpected error from ioprio_set() of {}", unexpected)
}
}
else
{
unreachable_code(format_args!("Unexpected result of {} from ioprio_get()", result))
}
}
#[inline(always)]
fn parse_ioprio_result(ioprio: i32) -> Result<Option<Self>, &'static str>
{
debug_assert!(ioprio >= 0);
if unlikely!(ioprio > u16::MAX as i32)
{
return Err("ioprio does not fit in an u16")
}
Self::parse_ioprio(ioprio as u16)
}
#[inline(always)]
fn parse_ioprio(ioprio: u16) -> Result<Option<Self>, &'static str>
{
use self::IoPriority::*;
let scheduling_class = IOPRIO_PRIO_CLASS(ioprio) as u8;
let scheduling_level = IOPRIO_PRIO_DATA(ioprio);
match scheduling_class
{
0 => if likely!(scheduling_level == 0)
{
Ok(None)
}
else
{
Err("IOPRIO_CLASS::IOPRIO_CLASS_NONE has a scheduling level")
},
1 => if likely!(scheduling_level <= 7)
{
Ok(Some(RealTime(unsafe { transmute(scheduling_level as u8) })))
}
else
{
Err("IOPRIO_CLASS::IOPRIO_CLASS_RT has a scheduling level greater than 7")
},
2 => if likely!(scheduling_level <= 7)
{
Ok(Some(BestEffort(unsafe { transmute(scheduling_level as u8) })))
}
else
{
Err("IOPRIO_CLASS::IOPRIO_CLASS_BE has a scheduling level greater than 7")
},
3 => if likely!(scheduling_level == 0)
{
Ok(Some(Idle))
}
else
{
Err("IOPRIO_CLASS::IOPRIO_CLASS_IDLE has a scheduling level")
},
_ => Err("Invalid IOPRIO_CLASS (scheduling class)")
}
}
}