timer_deque_rs/timer_portable/linux/
timer_fd_linux.rs1use std::borrow::Cow;
21use std::{fmt};
22use std::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, OwnedFd};
23use std::os::unix::prelude::RawFd;
24use std::task::Poll;
25
26use nix::fcntl::{FcntlArg, OFlag};
27use nix::{fcntl, libc};
28use nix::libc::itimerspec;
29
30
31use crate::nix::errno::Errno;
32use crate::timer_portable::portable_error::TimerPortResult;
33use crate::timer_portable::timer::{FdTimerRead, ModeTimeType, TimerReadRes};
34use crate::{map_portable_err, portable_err, AbsoluteTime};
35use crate::timer_portable::
36{
37 FdTimerCom, TimerExpMode, TimerFlags, TimerType
38};
39
40
41#[derive(Debug)]
49pub struct TimerFdInternal
50{
51 label: Cow<'static, str>,
53
54 timer_fd: OwnedFd,
56}
57
58impl fmt::Display for TimerFdInternal
59{
60 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
61 {
62 write!(f, "{}", self.timer_fd.as_raw_fd())
63 }
64}
65
66impl AsFd for TimerFdInternal
67{
68 fn as_fd(&self) -> BorrowedFd<'_>
69 {
70 return self.timer_fd.as_fd();
71 }
72}
73
74impl AsRawFd for TimerFdInternal
75{
76 fn as_raw_fd(&self) -> RawFd
77 {
78 return self.timer_fd.as_raw_fd();
79 }
80}
81
82impl Eq for TimerFdInternal {}
83
84impl PartialEq for TimerFdInternal
85{
86 fn eq(&self, other: &Self) -> bool
87 {
88 return self.timer_fd.as_raw_fd() == other.timer_fd.as_raw_fd();
89 }
90}
91
92impl PartialEq<RawFd> for TimerFdInternal
93{
94 fn eq(&self, other: &RawFd) -> bool
95 {
96 return self.timer_fd.as_raw_fd() == *other;
97 }
98}
99
100impl PartialEq<str> for TimerFdInternal
101{
102 fn eq(&self, other: &str) -> bool
103 {
104 return self.label == other;
105 }
106}
107
108impl AsRef<str> for TimerFdInternal
109{
110 fn as_ref(&self) -> &str
111 {
112 return &self.label;
113 }
114}
115
116impl Ord for TimerFdInternal
117{
118 fn cmp(&self, other: &Self) -> std::cmp::Ordering
119 {
120 return self.timer_fd.as_raw_fd().cmp(&other.timer_fd.as_raw_fd());
121 }
122}
123
124impl PartialOrd for TimerFdInternal
125{
126 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering>
127 {
128 return Some(self.cmp(other));
129 }
130}
131
132impl FdTimerRead for TimerFdInternal
133{
134 #[inline]
135 fn read(&self) -> TimerPortResult<TimerReadRes<u64>>
136 {
137 let mut timer_overfl = [0u8; size_of::<u64>()];
138
139 loop
140 {
141 let ret =
142 nix::unistd::read(&self.timer_fd, &mut timer_overfl);
143
144 if let Ok(_) = ret
145 {
146 let overl: u64 = u64::from_ne_bytes(timer_overfl);
147
148 return Ok(TimerReadRes::Ok(overl));
149 }
150 else if let Err(Errno::EINTR) = ret
151 {
152 continue;
153 }
154 else if let Err(Errno::EAGAIN) = ret
155 {
156 return Ok(TimerReadRes::WouldBlock);
158 }
159 else if let Err(Errno::ECANCELED) = ret
160 {
161 return Ok(TimerReadRes::Cancelled);
162 }
163 else if let Err(e) = ret
164 {
165 portable_err!(e, "read timer overflow error for timer: '{}'", self.label)
166 }
167 }
168 }
169}
170
171impl FdTimerCom for TimerFdInternal
172{
173 fn new(label: Cow<'static, str>, timer_type: TimerType, timer_flags: TimerFlags) -> TimerPortResult<Self>
174 {
175 let timer_fd =
176 unsafe { libc::timerfd_create(timer_type.into(), timer_flags.bits()) };
177
178 if timer_fd == -1
179 {
180 portable_err!(Errno::last(), "timer: '{}', timerfd_create failed with error", label);
181 }
182
183 return Ok(
184 Self
185 {
186 label:
187 label,
188 timer_fd:
189 unsafe { OwnedFd::from_raw_fd(timer_fd) },
190 }
193 );
194 }
195
196 fn set_time<TIMERTYPE: ModeTimeType>(&self, timer_exp: TimerExpMode<TIMERTYPE>) -> TimerPortResult<()>
197 {
198 let flags = TIMERTYPE::get_flags().bits();
202 let timer_value: itimerspec = timer_exp.into();
203
204 let res =
205 unsafe
206 {
207 libc::timerfd_settime(self.timer_fd.as_raw_fd(), flags,
208 &timer_value, core::ptr::null_mut())
209 };
210
211 if res == -1
212 {
213 portable_err!(Errno::last(), "can not init timer: '{}'", self.label);
214 }
215
216 return Ok(());
217 }
218
219 fn unset_time(&self) -> TimerPortResult<()>
220 {
221 let mut timer_value: itimerspec = unsafe { std::mem::zeroed() };
223
224 let res =
225 unsafe
226 {
227 libc::timerfd_gettime(self.timer_fd.as_raw_fd(),
228 &mut timer_value as *mut _ as *mut itimerspec)
229 };
230
231 if res == -1
232 {
233 portable_err!(Errno::last(), "can not timerfd_gettime for timer: '{}'", self.label);
234 }
235
236 let timer_mode = TimerExpMode::<AbsoluteTime>::from(timer_value);
237
238 if TimerExpMode::<AbsoluteTime>::reset() == timer_mode
239 {
240 return Ok(());
242 }
243
244 let timer_value: itimerspec = TimerExpMode::<AbsoluteTime>::reset().into();
247
248 let res =
249 unsafe
250 {
251 libc::timerfd_settime(self.timer_fd.as_raw_fd(), 0,
252 &timer_value, core::ptr::null_mut())
253 };
254
255 if res == -1
256 {
257 portable_err!(Errno::last(), "can not unset timer: '{}'", self.label);
258 }
259
260 return Ok(());
261 }
262
263 fn set_nonblocking(&self, flag: bool) -> TimerPortResult<()>
264 {
265 let mut fl =
266 OFlag::from_bits_retain(
267 fcntl::fcntl(&self.timer_fd, FcntlArg::F_GETFL)
268 .map_err(|e|
269 map_portable_err!(e, "timer: '{}', fcntl F_GETFL failed", self.label)
270 )?
271 );
272
273 fl.set(OFlag::O_NONBLOCK, flag);
274
275 fcntl::fcntl(&self.timer_fd, FcntlArg::F_SETFL(fl))
276 .map_err(|e|
277 map_portable_err!(e, "timer: '{}', fcntl F_SETFL failed", self.label)
278 )?;
279
280 return Ok(());
281 }
282
283 fn is_nonblocking(&self) -> TimerPortResult<bool>
284 {
285 let fl =
286 OFlag::from_bits_retain(
287 fcntl::fcntl(&self.timer_fd, FcntlArg::F_GETFL)
288 .map_err(|e|
289 map_portable_err!(e, "timer: '{}', fcntl F_GETFL failed", self.label)
290 )?
291 );
292
293 return Ok(fl.intersects(OFlag::O_NONBLOCK));
294 }
295}
296
297
298impl TimerFdInternal
299{
300
301}
302
303impl Future for &TimerFdInternal
304{
305 type Output = TimerPortResult<TimerReadRes<u64>>;
306
307 fn poll(self: std::pin::Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> std::task::Poll<Self::Output>
308 {
309 let res = self.read();
310
311 if let Ok(TimerReadRes::WouldBlock) = res
312 {
313 cx.waker().wake_by_ref();
314
315 return Poll::Pending;
316 }
317 else
318 {
319 return Poll::Ready(res);
320 }
321 }
322}
323
324impl Future for TimerFdInternal
325{
326 type Output = TimerPortResult<TimerReadRes<u64>>;
327
328 fn poll(self: std::pin::Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> std::task::Poll<Self::Output>
329 {
330 let res = self.read();
331
332 if let Ok(TimerReadRes::WouldBlock) = res
333 {
334 cx.waker().wake_by_ref();
335
336 return Poll::Pending;
337 }
338 else
339 {
340 return Poll::Ready(res);
341 }
342 }
343}
344
345