timer_deque_rs/timer_portable/poll.rs
1/*-
2 * timer-deque-rs - a Rust crate which provides timer and timer queues based on target OS
3 * functionality.
4 *
5 * Copyright (C) 2025 Aleksandr Morozov alex@nixd.org
6 * 4neko.org alex@4neko.org
7 *
8 * The timer-rs crate can be redistributed and/or modified
9 * under the terms of either of the following licenses:
10 *
11 * 1. the Mozilla Public License Version 2.0 (the “MPL”) OR
12 *
13 * 2. EUROPEAN UNION PUBLIC LICENCE v. 1.2 EUPL © the European Union 2007, 2016
14 */
15
16use std::{fmt, mem::discriminant, ops, os::fd::{AsFd, RawFd}, sync::{Arc, Weak}};
17
18
19use nix::{errno::Errno, sys::eventfd::EventFd};
20
21use crate::
22{
23 error::{TimerError, TimerErrorType, TimerResult},
24 map_timer_err,
25 timer_err,
26 timer_portable::DefaultEventWatch
27};
28
29/// Defines a result which may occure when polling the timer's FDs
30/// (for a single event).
31#[derive(Debug)]
32pub struct PollResult
33{
34 events: Vec<PollEventType>,
35}
36
37impl ops::Index<usize> for PollResult
38{
39 type Output = PollEventType;
40
41 fn index(&self, index: usize) -> &Self::Output
42 {
43 return &self.events[index];
44 }
45}
46
47impl fmt::Display for PollResult
48{
49 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
50 {
51 write!(f, "{:?}", self.events)
52 }
53}
54
55impl PollResult
56{
57 #[inline]
58 pub
59 fn new_none() -> Self
60 {
61 return Self{ events: Vec::new()};
62 }
63
64 #[inline]
65 pub
66 fn new(evs: usize) -> Self
67 {
68 return Self{ events: Vec::with_capacity(evs) };
69 }
70
71 #[inline]
72 pub
73 fn push(&mut self, pet: PollEventType)
74 {
75 self.events.push(pet);
76 }
77
78 pub
79 fn is_none(&self) -> bool
80 {
81 return self.events.is_empty();
82 }
83
84 pub
85 fn len(&self) -> usize
86 {
87 return self.events.len();
88 }
89
90 pub
91 fn pop(&mut self) -> Option<PollEventType>
92 {
93 return self.events.pop();
94 }
95
96 pub
97 fn into_inner(self) -> Vec<PollEventType>
98 {
99 return self.events;
100 }
101}
102
103/// Defines a result which may occure when polling the timer's FDs
104/// (for a multiple events).
105#[derive(Debug, PartialEq, Eq)]
106pub enum PollEventType
107{
108 /// Timer which generates time up event.
109 Some(RawFd),
110
111 /// Returned if timer (0 - [RawFd]) was removed.
112 TimerRemoved(RawFd),
113
114 /// Sub error which occured during `read()`.
115 SubError(TimerError)
116}
117
118impl fmt::Display for PollEventType
119{
120 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
121 {
122 match self
123 {
124 Self::Some(items) =>
125 write!(f, "event fd: {:?}", items),
126 Self::TimerRemoved(fd) =>
127 write!(f, "timer {} removed", fd),
128 Self::SubError(err) =>
129 write!(f, "sub error: {}", err)
130 }
131 }
132}
133
134impl PollEventType
135{
136 pub
137 fn unwrap_some(self) -> RawFd
138 {
139 let Self::Some(rawfd) = self
140 else
141 {
142 panic!("expected Some, got: {}", self)
143 };
144
145 return rawfd;
146 }
147
148 pub
149 fn is_some(&self) -> bool
150 {
151 return
152 discriminant(self) == discriminant(&Self::Some(0));
153 }
154}
155
156/// A trait which is implemented by the timer instance which will be used by the
157/// [TimerPoll] to bind the timer.
158pub trait AsTimerFd: fmt::Display + AsFd
159{
160 /// Should return the upgraded reference to which instance it is bind.
161 ///
162 /// # Returns
163 ///
164 /// A [Option] is returned where:
165 ///
166 /// * [Option::Some] is returned if [Weak] to [Arc] was successfull or
167 /// the record is set.
168 ///
169 /// * [Option::None] is returned if unset or upgrade failed. In case of latter,
170 /// this should not happen if called from the same instance.
171 fn get_bind(&self) -> Option<Arc<DefaultEventWatch>>;
172
173 /// Regesters `poller` [DefaultEventWatch] on the timer's record.
174 ///
175 /// # Arguments
176 ///
177 /// * `timer_weak_ref` - a [Weak] reference to [Arc] of [DefaultEventWatch] of the
178 /// current instance.
179 fn bind_poll(&self, timer_weak_ref: Weak<DefaultEventWatch>);
180
181 /// Removes bind fromt the timer.
182 fn unbind_poll(&self);
183}
184
185/// A trait which is implemented by the poll instance in order for the timer
186/// instance to be able to unregister itself if the timer instance becomes invalid by accident
187/// or on purpose without removing it from the the [TimerPoll].
188///
189/// This is a subset of the [TimerPollOps] trait.
190pub trait TimerPollOpsUnregister: fmt::Display
191{
192 /// Removes the specified timer `timer` (which must implement [AsTimerFd]) from
193 /// the polling instance.
194 fn unregister<T: AsTimerFd>(&self, timer: &T) -> TimerResult<()>;
195}
196
197/// A standart functions for each timer.
198pub trait TimerPollOps: TimerPollOpsUnregister
199{
200 /// Creates new default instance.
201 ///
202 /// # Returns
203 ///
204 /// A [TimerResult] is returned with instance on success.
205 fn new() -> TimerResult<Self> where Self: Sized;
206
207 /// Adds the timer to the event monitor. It accepts any reference to instance which
208 /// implements [AsFd] and it is not limited specificly to timers. Maybe later this
209 /// behaviour will me modified.
210 ///
211 /// # Arguments
212 ///
213 /// * `timer` - `T` where impl [AsTimerFd] a timer instance. The provided
214 /// FD will be polled for [EpollFlags::EPOLLIN] event types.
215 ///
216 /// # Returns
217 ///
218 /// A [TimerResult] i.e [Result] is returned with error description in case of error.
219 fn add<T: AsTimerFd>(&self, timer: &T) -> TimerResult<()>;
220
221 /// Removes the specific timer's FD from the event monitor.
222 ///
223 /// # Arguments
224 ///
225 /// * `timer` - `T` where impl [AsTimerFd] a timer instance.
226 ///
227 /// # Returns
228 ///
229 /// A [TimerResult] i.e [Result] is returned with error description in case of error.
230 fn delete<T: AsTimerFd>(&self, timer: &T) -> TimerResult<()>;
231
232 /// Polls the event monitor for events. Depending on the `timeout` the behaviour will
233 /// be different.
234 ///
235 ///
236 /// # Arguments
237 ///
238 /// * `timeout` - poll timeout. If set to [Option::None] will block the current thread.
239 /// If set to [Option::Some] with inner value `0` will return immidiatly. The
240 /// timeout is set in `miliseconds`.
241 ///
242 /// # Returns
243 ///
244 /// A [TimerResult] i.e [Result] is returned with
245 ///
246 /// * [Result::Ok] with the [PollResult] where:
247 ///
248 /// * [PollResult::Some] with the [Vec] with the [RawFd] of the timer's where the event has
249 /// happened.
250 ///
251 /// * [PollResult::None] if no events happened.
252 ///
253 /// * [PollResult::TimerRemoved] if timer was removed during polling operation. Otherwise,
254 /// it will not be returned. If timer was cancelled and another timer times out, the
255 /// `TimerRemoved` will be supressed in favor of the [PollResult::Some].
256 ///
257 /// * [Result::Err] with error description.
258 fn poll(&self, timeout: Option<i32>) -> TimerResult<PollResult>;
259
260 /// Returns the amount of timer's FDs
261 fn get_count(&self) -> usize;
262
263 /// Provides a [Weak] reference to the wakeup [EventFd].
264 fn get_poll_interruptor(&self) -> PollInterrupt;
265
266 /// Attempts to interrupt the poll operaiton. If successfull returns `true`.
267 fn interrupt_poll(&self) -> bool;
268}
269
270#[derive(Debug)]
271pub struct PollInterruptAq(Arc<EventFd>);
272
273impl PollInterruptAq
274{
275 pub
276 fn interrupt(&self) -> TimerResult<()>
277 {
278 return
279 self
280 .0
281 .write(1)
282 .map_err(|e|
283 map_timer_err!(TimerErrorType::EPoll(e), "can not interrupt POLL!")
284 )
285 .map(|_| ());
286 }
287
288 pub
289 fn interrupt_drop(self) -> TimerResult<()>
290 {
291 return
292 self.interrupt();
293 }
294}
295
296#[derive(Debug, Clone)]
297pub struct PollInterrupt(Weak<EventFd>);
298
299impl PollInterrupt
300{
301 pub
302 fn new(ev_weak: Weak<EventFd>) -> Self
303 {
304 return Self(ev_weak);
305 }
306
307 pub
308 fn aquire(&self) -> TimerResult<PollInterruptAq>
309 {
310 return
311 self
312 .0
313 .upgrade()
314 .ok_or_else(||
315 map_timer_err!(TimerErrorType::EPoll(Errno::EINVAL), "timer poll has gone and not active!")
316 )
317 .map(|v| PollInterruptAq(v));
318 }
319}
320
321/// A main instance which initializes the event listeners from the registered
322/// timers.
323#[repr(transparent)]
324#[derive(Debug)]
325pub struct TimerPoll(Arc<DefaultEventWatch>);
326
327impl fmt::Display for TimerPoll
328{
329 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
330 {
331 write!(f, "{}", self.0.as_ref())
332 }
333}
334
335impl TimerPoll
336{
337 #[inline]
338 fn get_timer(&self) -> &DefaultEventWatch
339 {
340 return &self.0;
341 }
342
343 /// Creates new instance of the event listener.
344 pub
345 fn new() -> TimerResult<Self>
346 {
347 return Ok( Self( Arc::new(DefaultEventWatch::new()?) ) );
348 }
349
350 /// Adds the timer to the event monitor. It accepts any reference to instance which
351 /// implements [AsFd] and it is not limited specificly to timers. Maybe later this
352 /// behaviour will me modified.
353 ///
354 /// # Arguments
355 ///
356 /// * `timer` - `T` where impl [AsTimerFd] a timer instance. The provided
357 /// FD will be polled for [EpollFlags::EPOLLIN] event types.
358 ///
359 /// # Returns
360 ///
361 /// A [TimerResult] i.e [Result] is returned with error description in case of error.
362 pub
363 fn add<T: AsTimerFd>(&self, timer: &T) -> TimerResult<()>
364 {
365 if timer.get_bind().is_some() == true
366 {
367 timer_err!(TimerErrorType::AlreadyPolled, "timer: '{}', already binded to polling instance: '{}'", timer, self);
368 }
369
370 self.get_timer().add(timer)?;
371
372 let poll_inst = Arc::downgrade(&self.0);
373
374 // bind timer
375 timer.bind_poll(poll_inst);
376
377 return Ok(());
378 }
379
380 /// Removes the specific timer's FD from the event monitor.
381 ///
382 /// # Arguments
383 ///
384 /// * `timer` - `T` where impl [AsTimerFd] a timer instance.
385 ///
386 /// # Returns
387 ///
388 /// A [TimerResult] i.e [Result] is returned with error description in case of error.
389 pub
390 fn delete<T: AsTimerFd>(&self, timer: &T) -> TimerResult<()>
391 {
392 let Some(binded_to) = timer.get_bind()
393 else
394 {
395 timer_err!(TimerErrorType::NotFound, "timer: '{}', is not binded to polling instance: {}", timer, self);
396 };
397
398 // check if it belongs to this instance
399 if binded_to != self.0
400 {
401 timer_err!(TimerErrorType::BelongOtherInstance, "timer: '{}', is not binded to this instance: {}", timer, self);
402 }
403
404 // unbind
405 timer.unbind_poll();
406
407 // remove from poll
408 return self.get_timer().delete(timer);
409 }
410
411 /// Polls the event monitor for events. Depending on the `timeout` the behaviour will
412 /// be different.
413 ///
414 /// # Arguments
415 ///
416 /// * `timeout` - poll timeout. If set to [Option::None] will block the current thread.
417 /// If set to [Option::Some] with inner value `0` will return immidiatly. The
418 /// timeout is set in `miliseconds`.
419 ///
420 /// # Returns
421 ///
422 /// A [TimerResult] i.e [Result] is returned with
423 ///
424 /// * [Result::Ok] with the [Option] where:
425 ///
426 /// * [Option::Some] with the [Vec] with the [RawFd] of the timer's where the event has
427 /// happened.
428 ///
429 /// * [Option::None] if no events happened.
430 ///
431 /// * [Result::Err] with error description.
432 #[inline]
433 pub
434 fn poll(&self, timeout: Option<i32>) -> TimerResult<PollResult>
435 {
436 return self.get_timer().poll(timeout);
437 }
438
439 #[inline]
440 pub
441 fn get_poll_interruptor(&self) -> PollInterrupt
442 {
443 return self.get_timer().get_poll_interruptor();
444 }
445
446 #[inline]
447 pub
448 fn interrupt_poll(&self) -> bool
449 {
450 return self.get_timer().interrupt_poll();
451 }
452}
453
454#[cfg(test)]
455mod tests
456{
457
458
459 use std::sync::Arc;
460
461 use crate::{timer_portable::{poll::{AsTimerFd, TimerPollOps}, timer::TimerFd, FdTimerCom, TimerFlags, TimerType}, TimerPoll};
462
463 #[test]
464 fn test_poll0()
465 {
466 let poll = TimerPoll::new().unwrap();
467
468 let tm_fd0 = TimerFd::new("test0".into(), TimerType::CLOCK_REALTIME, TimerFlags::TFD_NONBLOCK).unwrap();
469
470 poll.add(&tm_fd0).unwrap();
471
472 assert_eq!(tm_fd0.get_bind().is_some(), true);
473
474 // check dup
475 let res = poll.add(&tm_fd0);
476 assert_eq!(res.is_err(), true);
477 println!("passed: {}", res.err().unwrap());
478
479 // check timer drop
480 drop(tm_fd0);
481
482 assert_eq!(poll.get_timer().get_count(), 0);
483 assert_eq!(Arc::weak_count(&poll.0), 0);
484 println!("passed: weak count: {}, count: {}", Arc::weak_count(&poll.0), poll.get_timer().get_count());
485
486 // check poll instance deinit
487 let tm_fd0 = TimerFd::new("test0".into(), TimerType::CLOCK_REALTIME, TimerFlags::TFD_NONBLOCK).unwrap();
488 poll.add(&tm_fd0).unwrap();
489
490 assert_eq!(tm_fd0.get_bind().is_some(), true);
491
492 drop(poll);
493
494 let res = tm_fd0.get_bind();
495 assert_eq!(res.is_none(), true);
496 println!("passed: timer event watch is none;")
497 }
498}