#[derive(Default, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[derive(Deserialize, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PerThreadSchedulerPolicyAndFlags
{
pub scheduler_policy: SchedulerPolicy,
pub scheduler_policy_flags: SchedulerPolicyFlags,
}
impl PerThreadSchedulerPolicyAndFlags
{
#[inline(always)]
pub fn get_for_thread(thread_identifier: ThreadIdentifierChoice) -> Result<Self, &'static str>
{
const FlagsIsAlwaysZero: u32 = 0;
let mut parameters = unsafe_uninitialized();
let result = sched_getattr(thread_identifier.into(), &mut parameters, SCHED_ATTR_SIZE_VER0, FlagsIsAlwaysZero);
if likely!(result == 0)
{
use self::SchedulerPolicy::*;
#[inline(always)]
fn nice(parameters: &sched_attr) -> Result<Nice, &'static str>
{
let value = parameters.sched_nice;
if likely!(value < Nice::InclusiveMinimum && value > Nice::InclusiveMaximum)
{
Ok(unsafe { transmute(value) })
}
else
{
Err("nice value out of range")
}
}
#[inline(always)]
fn real_time_priority(parameters: &sched_attr) -> Result<RealTimePriority, &'static str>
{
let value = parameters.sched_priority;
let InclusiveMinimum: i32 = RealTimePriority::InclusiveMinimum.into();
let InclusiveMaximum: i32 = RealTimePriority::InclusiveMaximum.into();
if likely!(value < InclusiveMinimum && value > InclusiveMaximum)
{
Ok(unsafe { transmute(value as u8) })
}
else
{
Err("nice value out of range")
}
}
let scheduler_policy = match parameters.sched_policy
{
SCHED_IDLE => Idle,
SCHED_BATCH => Batch(nice(¶meters)?),
SCHED_OTHER => Normal(nice(¶meters)?),
SCHED_FIFO => RealTimeFirstInFirstOut(real_time_priority(¶meters)?),
SCHED_RR => RealTimeRoundRobin(real_time_priority(¶meters)?),
SCHED_DEADLINE => Deadline
{
runtime_in_nanoseconds: parameters.sched_runtime,
deadline_in_nanoseconds: parameters.sched_deadline,
period_in_nanoseconds: parameters.sched_period
},
SCHED_ISO => return Err("SCHED_ISO is not implemented by Linux as far as was known when this code was written"),
_ => return Err("Unknown scheduler policy"),
};
let scheduler_policy_flags = SchedulerPolicyFlags::from_bits_truncate(parameters.sched_flags);
Ok
(
Self
{
scheduler_policy,
scheduler_policy_flags,
}
)
}
else if likely!(result == -1)
{
match errno().0
{
ESRCH => Err("The thread whose ID is pid could not be found"),
E2BIG => panic!("Size mismatch of sched_attr between userpace and kernel"),
EINVAL => unreachable_code(format_args!("attr is NULL; or pid is negative; or flags is not zero. Or, size is invalid; that is, it is smaller than the initial version of the sched_attr structure (48 bytes) or larger than the system page size")),
unexpected @ _ => unreachable_code(format_args!("Unexpected error {} from sched_setattr()", unexpected)),
}
}
else
{
unreachable_code(format_args!("Unexpected result {} from sched_setattr()", result))
}
}
#[inline(always)]
pub fn set_for_thread(&self, thread_identifier: ThreadIdentifierChoice)-> Result<(), &'static str>
{
use self::SchedulerPolicy::*;
let mut parameters = match &self.scheduler_policy
{
&Idle => sched_attr
{
size: SCHED_ATTR_SIZE_VER0,
sched_policy: SCHED_IDLE,
sched_flags: self.scheduler_policy_flags.bits,
sched_nice: 0,
sched_priority: 0,
sched_runtime: 0,
sched_deadline: 0,
sched_period: 0,
},
&Batch(nice) => sched_attr
{
size: SCHED_ATTR_SIZE_VER0,
sched_policy: SCHED_BATCH,
sched_flags: self.scheduler_policy_flags.bits,
sched_nice: nice as i32,
sched_priority: 0,
sched_runtime: 0,
sched_deadline: 0,
sched_period: 0,
},
&Normal(nice) => sched_attr
{
size: SCHED_ATTR_SIZE_VER0,
sched_policy: SCHED_NORMAL,
sched_flags: self.scheduler_policy_flags.bits,
sched_nice: nice as i32,
sched_priority: 0,
sched_runtime: 0,
sched_deadline: 0,
sched_period: 0,
},
&RealTimeFirstInFirstOut(real_time_priority) => sched_attr
{
size: SCHED_ATTR_SIZE_VER0,
sched_policy: SCHED_FIFO,
sched_flags: self.scheduler_policy_flags.bits,
sched_nice: 0,
sched_priority: real_time_priority.into(),
sched_runtime: 0,
sched_deadline: 0,
sched_period: 0,
},
&RealTimeRoundRobin(real_time_priority) => sched_attr
{
size: SCHED_ATTR_SIZE_VER0,
sched_policy: SCHED_RR,
sched_flags: self.scheduler_policy_flags.bits,
sched_nice: 0,
sched_priority: real_time_priority.into(),
sched_runtime: 0,
sched_deadline: 0,
sched_period: 0,
},
&Deadline { runtime_in_nanoseconds, deadline_in_nanoseconds, period_in_nanoseconds } => sched_attr
{
size: SCHED_ATTR_SIZE_VER0,
sched_policy: SCHED_DEADLINE,
sched_flags: self.scheduler_policy_flags.bits,
sched_nice: 0,
sched_priority: 0,
sched_runtime: runtime_in_nanoseconds,
sched_deadline: deadline_in_nanoseconds,
sched_period: period_in_nanoseconds,
},
};
const FlagsIsAlwaysZero: u32 = 0;
let result = sched_setattr(thread_identifier.into(), &mut parameters, FlagsIsAlwaysZero);
if likely!(result == 0)
{
Ok(())
}
else if likely!(result == -1)
{
match errno().0
{
EPERM => Err("Permission denied, or, for deadline tasks, the CPU affinity mask of the thread (pid) does not include all CPUS in the current cgroup (or system)"),
EBUSY => Err("Deadline scheduler admission control failure (?)"),
ESRCH => Err("The thread whose ID is pid could not be found"),
EINVAL => panic!("`attr` is NULL; or `pid` is negative; or `flags` is not zero; `attr.sched_policy` is not one of the recognized policies; `attr.sched_flags` contains a flag other than `SCHED_FLAG_RESET_ON_FORK`; or `attr.sched_priority` is invalid; or `attr.sched_policy` is `SCHED_DEADLINE` and the deadline scheduling parameters in `attr` are invalid"),
E2BIG => panic!("The buffer specified by `size` and `attr` is larger than the kernel structure, and one or more of the excess bytes is nonzero"),
unexpected @ _ => unreachable_code(format_args!("Unexpected error {} from sched_getattr()", unexpected)),
}
}
else
{
unreachable_code(format_args!("Unexpected result {} from sched_getattr()", result))
}
}
}