1use core::fmt::Display;
45
46use iceoryx2_bb_elementary::enum_gen;
47use iceoryx2_bb_system_types::file_path::*;
48use iceoryx2_log::fail;
49use iceoryx2_pal_posix::posix::{errno::Errno, MemZeroedStruct};
50use iceoryx2_pal_posix::*;
51
52use crate::{
53 scheduler::{Scheduler, SchedulerConversionError},
54 signal::Signal,
55};
56
57#[derive(Debug, Clone, Copy, Eq, PartialEq)]
58pub enum ProcessExecutablePathError {
59 ContainsInvalidCharacters,
60 UnableToRead,
61}
62
63enum_gen! { ProcessSendSignalError
64 entry:
65 InsufficientPermissions,
66 UnknownProcessId,
67 UnknownError(i32)
68}
69
70enum_gen! { ProcessGetSchedulerError
71 entry:
72 InsufficientPermissions,
73 UnknownProcessId,
74 UnknownError(i32)
75
76 mapping:
77 SchedulerConversionError
78}
79
80enum_gen! { ProcessSetSchedulerError
81 entry:
82 InsufficientPermissions,
83 UnknownProcessId,
84 UnknownError(i32)
85
86 mapping:
87 SchedulerConversionError
88}
89
90enum_gen! {
91 ProcessError
96 generalization:
97 FailedToSetSchedulerSettings <= ProcessSetSchedulerError,
98 FailedToGetSchedulerSettings <= ProcessGetSchedulerError,
99 FailedToSendSignal <= ProcessSendSignalError
100}
101
102pub trait ProcessExt {
105 fn as_process(&self) -> Process;
106}
107
108impl ProcessExt for posix::pid_t {
109 fn as_process(&self) -> Process {
110 Process::from_pid(ProcessId::new(*self))
111 }
112}
113
114#[derive(Debug, Copy, Clone, PartialEq, Eq)]
116pub struct ProcessId(posix::pid_t);
117
118impl ProcessId {
119 pub fn new(value: posix::pid_t) -> Self {
121 ProcessId(value)
122 }
123
124 pub fn value(&self) -> posix::pid_t {
126 self.0
127 }
128}
129
130impl Display for ProcessId {
131 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
132 write!(f, "{}", self.0)
133 }
134}
135
136#[derive(Debug)]
138pub struct Process {
139 pid: ProcessId,
140}
141
142impl Process {
143 pub fn from_pid(pid: ProcessId) -> Process {
146 Process { pid }
147 }
148
149 pub fn from_self() -> Process {
151 Process {
152 pid: unsafe { ProcessId::new(posix::getpid()) },
153 }
154 }
155
156 pub fn from_parent() -> Process {
158 Process {
159 pid: unsafe { ProcessId::new(posix::getppid()) },
160 }
161 }
162
163 pub fn is_alive(&self) -> bool {
165 unsafe { posix::kill(self.pid.0, 0_i32) == 0 }
166 }
167
168 pub fn id(&self) -> ProcessId {
170 self.pid
171 }
172
173 pub fn executable(&self) -> Result<FilePath, ProcessExecutablePathError> {
175 let msg = "Unable to read executable path";
176 let mut buffer = [0u8; FilePath::max_len()];
177 let path_len =
178 unsafe { posix::proc_pidpath(self.pid.0, buffer.as_mut_ptr().cast(), buffer.len()) };
179 if path_len < 0 {
180 fail!(from self, with ProcessExecutablePathError::UnableToRead,
181 "{} since the name could not be acquired.", msg);
182 }
183
184 let path = fail!(from self,
185 when FilePath::new(&buffer[..(path_len as usize)]),
186 with ProcessExecutablePathError::ContainsInvalidCharacters,
187 "{} since the acquired name contains invalid characters.", msg);
188
189 Ok(path)
190 }
191
192 pub fn send_signal(&self, signal: Signal) -> Result<(), ProcessSendSignalError> {
194 if unsafe { posix::kill(self.pid.0, signal as i32) } == 0 {
195 return Ok(());
196 }
197
198 let msg = "Unable to send signal to process";
199 handle_errno!(ProcessSendSignalError, from self,
200 Errno::EPERM => (InsufficientPermissions, "{} due to insufficient permissions.", msg),
201 Errno::ESRCH => (UnknownProcessId, "{} since the process does not exist.", msg),
202 v => (UnknownError(v as i32), "{} since an unknown error occurred ({}).", msg,v)
203 );
204 }
205
206 pub fn get_priority(&self) -> Result<u8, ProcessGetSchedulerError> {
208 let msg = "Unable to acquire priority of process";
209 let scheduler = fail!(from self, when self.get_scheduler(), "{} due to a failure while getting the current scheduler of the process.", msg);
210
211 let mut param = posix::sched_param::new_zeroed();
212 if unsafe { posix::sched_getparam(self.pid.0, &mut param) } == 0 {
213 return Ok(scheduler.get_priority_from(¶m));
214 }
215
216 handle_errno!(ProcessGetSchedulerError, from self,
217 Errno::EPERM => (InsufficientPermissions, "{} due to insufficient permissions.", msg),
218 Errno::ESRCH => (UnknownProcessId, "{} since the process cannot be found on the system.", msg),
219 v => (UnknownError(v as i32), "{} since an unknown error occurred ({}).", msg, v)
220 );
221 }
222
223 pub fn set_priority(&mut self, priority: u8) -> Result<(), ProcessGetSchedulerError> {
225 let msg = "Unable to set process priority";
226 let scheduler = fail!(from self, when self.get_scheduler(), "{} due to a failure while acquiring the current process scheduler.", msg);
227 let mut param = posix::sched_param::new_zeroed();
228 param.sched_priority = scheduler.policy_specific_priority(priority);
229
230 if unsafe { posix::sched_setparam(self.pid.0, ¶m) } == 0 {
231 return Ok(());
232 }
233
234 handle_errno!(ProcessGetSchedulerError, from self,
235 Errno::EPERM => (InsufficientPermissions, "{} due to insufficient permissions.", msg),
236 Errno::ESRCH => (UnknownProcessId, "{} since the process cannot be found on the system.", msg),
237 v => (UnknownError(v as i32), "{} since an unknown error occurred ({}).", msg, v)
238 );
239 }
240
241 pub fn get_scheduler(&self) -> Result<Scheduler, ProcessGetSchedulerError> {
243 let msg = "Unable to acquire scheduler of process";
244 let v = unsafe { posix::sched_getscheduler(self.pid.0) };
245 if v != -1 {
246 return Ok(
247 fail!(from self, when Scheduler::from_int(v), "{} since the scheduler seems to be unknown.", msg),
248 );
249 }
250
251 handle_errno!(ProcessGetSchedulerError, from self,
252 Errno::EPERM => (InsufficientPermissions, "{} due to insufficient permissions.", msg),
253 Errno::ESRCH => (UnknownProcessId, "{} since the process cannot be found on the system.", msg),
254 v => (UnknownError(v as i32), "{} since an unknown error occurred ({}).", msg, v)
255 );
256 }
257
258 pub fn set_scheduler(
261 &mut self,
262 scheduler: Scheduler,
263 ) -> Result<Scheduler, ProcessSetSchedulerError> {
264 let msg = "Unable to set scheduler of process";
265 let mut param = posix::sched_param::new_zeroed();
266 param.sched_priority = scheduler.policy_specific_priority(0);
267 let former_scheduler =
268 unsafe { posix::sched_setscheduler(self.pid.0, scheduler as i32, ¶m) };
269
270 if former_scheduler != -1 {
271 return Ok(fail!(from self, when Scheduler::from_int(former_scheduler),
272 "The previous set up scheduler is not supported. New scheduler was successfully set but cannot reverted to previous scheduler."));
273 }
274
275 handle_errno!(ProcessSetSchedulerError, from self,
276 Errno::EPERM => (InsufficientPermissions, "{} due to insufficient permissions.", msg),
277 Errno::ESRCH => (UnknownProcessId, "{} since the process cannot be found on the system.", msg),
278 v => (UnknownError(v as i32), "{} since an unknown error occurred ({}).", msg,v)
279 );
280 }
281}