1use crate::sched::PreemptRtError::{PriorityAboveMax, PriorityBelowMin};
2use libc::{c_int, pid_t};
3use std::mem::MaybeUninit;
4use std::{fmt, result};
5use thiserror::Error;
6
7pub type Result<T> = result::Result<T, PreemptRtError>;
9
10#[derive(Debug, Error)]
11pub enum PreemptRtError {
12 #[error("c function returned errno: {0}")]
13 Errno(c_int),
14 #[error("unknown scheduler for value {0}")]
15 UnknownScheduler(c_int),
16 #[error("priority {0} is higher than max priority {1}")]
17 PriorityAboveMax(c_int, c_int),
18 #[error("priority {0} is lower than min priority {1}")]
19 PriorityBelowMin(c_int, c_int),
20}
21
22fn handle_errno(result: c_int) -> Result<c_int> {
23 if result == -1 {
24 Err(PreemptRtError::Errno(unsafe { *libc::__errno_location() }))
25 } else {
26 Ok(result)
27 }
28}
29
30#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
31pub struct Pid(pid_t);
32
33impl Pid {
34 pub const fn current_thread() -> Self {
35 Pid(0)
36 }
37}
38
39impl From<Pid> for pid_t {
40 fn from(pid: Pid) -> Self {
41 pid.0
42 }
43}
44
45impl fmt::Display for Pid {
46 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
47 fmt::Display::fmt(&self.0, f)
48 }
49}
50
51#[repr(i32)]
52#[allow(non_camel_case_types)] #[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
54pub enum Scheduler {
58 SCHED_NORMAL = libc::SCHED_NORMAL,
60 SCHED_FIFO = libc::SCHED_FIFO,
64 SCHED_RR = libc::SCHED_RR,
66 SCHED_BATCH = libc::SCHED_BATCH,
70 SCHED_IDLE = libc::SCHED_IDLE,
73 SCHED_DEADLINE = libc::SCHED_DEADLINE,
77}
78
79impl TryFrom<c_int> for Scheduler {
80 type Error = PreemptRtError;
81
82 fn try_from(value: c_int) -> Result<Self> {
83 match value {
84 libc::SCHED_NORMAL => Ok(Scheduler::SCHED_NORMAL),
85 libc::SCHED_FIFO => Ok(Scheduler::SCHED_FIFO),
86 libc::SCHED_RR => Ok(Scheduler::SCHED_RR),
87 libc::SCHED_BATCH => Ok(Scheduler::SCHED_BATCH),
88 libc::SCHED_IDLE => Ok(Scheduler::SCHED_IDLE),
89 libc::SCHED_DEADLINE => Ok(Scheduler::SCHED_DEADLINE),
90 _ => Err(PreemptRtError::UnknownScheduler(value)),
91 }
92 }
93}
94
95impl Scheduler {
96 pub fn priority_max(&self) -> Result<c_int> {
98 let res = unsafe { libc::sched_get_priority_max(*self as c_int) };
99 handle_errno(res)
100 }
101
102 pub fn priority_min(&self) -> Result<c_int> {
104 let res = unsafe { libc::sched_get_priority_min(*self as c_int) };
105 handle_errno(res)
106 }
107
108 pub fn with_priority(self, priority: c_int) -> Result<ParameterizedScheduler> {
109 let max = self.priority_max()?;
110 let min = self.priority_min()?;
111 if priority > max {
112 Err(PriorityAboveMax(priority, max).into())
113 } else if priority < min {
114 Err(PriorityBelowMin(priority, min).into())
115 } else {
116 Ok(ParameterizedScheduler {
117 scheduler: self,
118 params: SchedulerParams { priority },
119 })
120 }
121 }
122}
123
124#[repr(C)]
125#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
126pub struct SchedulerParams {
129 pub priority: c_int,
131}
132
133impl From<SchedulerParams> for libc::sched_param {
134 #[cfg(not(any(target_env = "musl", target_env = "ohos")))]
135 fn from(param: SchedulerParams) -> Self {
136 libc::sched_param {
137 sched_priority: param.priority,
138 }
139 }
140
141 #[cfg(any(target_env = "musl", target_env = "ohos"))]
142 fn from(param: SchedulerParams) -> Self {
143 let ts_zero = libc::timespec {
144 tv_sec: 0,
145 tv_nsec: 0,
146 };
147 libc::sched_param {
150 sched_priority: param.priority,
151 sched_ss_init_budget: ts_zero.clone(),
152 sched_ss_low_priority: 0,
153 sched_ss_repl_period: ts_zero.clone(),
154 sched_ss_max_repl: 0,
155 }
156 }
157}
158
159impl From<libc::sched_param> for SchedulerParams {
160 fn from(param: libc::sched_param) -> Self {
161 SchedulerParams {
162 priority: param.sched_priority,
163 }
164 }
165}
166
167pub trait IntoSchedParam {
168 fn into_sched_param(self) -> SchedulerParams;
169}
170
171impl IntoSchedParam for i32 {
172 fn into_sched_param(self) -> SchedulerParams {
173 SchedulerParams {
174 priority: self as c_int,
175 }
176 }
177}
178
179impl<T: IntoSchedParam> IntoSchedParam for Option<T> {
180 fn into_sched_param(self) -> SchedulerParams {
181 match self {
182 None => SchedulerParams { priority: 0 },
183 Some(param) => param.into_sched_param(),
184 }
185 }
186}
187
188#[derive(Debug, Clone)]
189pub struct ParameterizedScheduler {
190 scheduler: Scheduler,
191 params: SchedulerParams,
192}
193
194impl ParameterizedScheduler {
195 pub fn set_on(self, pid: Pid) -> Result<()> {
196 set_scheduler(pid, self.scheduler, self.params)
197 }
198
199 pub fn set_current(self) -> Result<()> {
200 self.set_on(Pid::current_thread())
201 }
202}
203
204pub fn get_scheduler(pid: Pid) -> Result<Scheduler> {
207 let res = unsafe { libc::sched_getscheduler(pid.into()) };
208 handle_errno(res).and_then(Scheduler::try_from)
209}
210
211pub fn set_scheduler(pid: Pid, scheduler: Scheduler, param: SchedulerParams) -> Result<()> {
221 let param: libc::sched_param = param.into();
222 let res = unsafe { libc::sched_setscheduler(pid.into(), scheduler as c_int, ¶m) };
223
224 handle_errno(res).map(drop)
225}
226
227pub fn get_scheduler_params(pid: Pid) -> Result<SchedulerParams> {
230 let mut param: MaybeUninit<libc::sched_param> = MaybeUninit::uninit();
231 let res = unsafe { libc::sched_getparam(pid.into(), param.as_mut_ptr()) };
232
233 handle_errno(res).map(|_| unsafe { param.assume_init() }.into())
234}
235pub fn set_scheduler_params(pid: Pid, param: SchedulerParams) -> Result<()> {
241 let param: libc::sched_param = param.into();
242 let res = unsafe { libc::sched_setparam(pid.into(), ¶m) };
243 handle_errno(res).map(drop)
244}