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. The MIT License (MIT)
14 *                     
15 *   3. EUROPEAN UNION PUBLIC LICENCE v. 1.2 EUPL © the European Union 2007, 2016
16 */
17
18
19
20use std::{cell::OnceCell, fmt, sync::{Arc, Weak}};
21
22#[cfg(target_family = "unix")]
23use nix::{errno::Errno, sys::eventfd::EventFd};
24
25use crate::
26{
27    FdTimerCom, 
28    TimerReadRes, 
29    error::{TimerErrorType, TimerResult}, 
30    map_timer_err, 
31    timer_portable::
32    {
33        TimerFd, TimerId, portable_error::TimerPortableErr, timer::{FdTimerMarker}
34    }
35};
36
37#[cfg(target_family = "unix")]
38pub use super::unix::TimerEventWatch;
39
40#[cfg(target_family = "unix")]
41pub type DefaultEventWatch = TimerEventWatch;
42
43// ---- WINDOWS ----
44#[cfg(target_os = "windows")]
45pub use super::windows::timer_poll::TimerEventWatch;
46
47#[cfg(target_os = "windows")]
48pub type DefaultEventWatch = TimerEventWatch;
49
50#[cfg(target_os = "windows")]
51use super::windows::EventFd;
52
53#[cfg(target_family = "windows")]
54use std::os::windows::io::AsHandle;
55// -----/WINDOWS/----
56
57
58/// A `poll` result.
59/// 
60/// `0` - [TimerFd] is a source of the event.
61#[derive(Debug, PartialEq, Eq)]
62pub enum PollEventType
63{
64    /// An event from timer. It contains a [TimerReadRes] which is received
65    /// from `read()`.
66    TimerRes(TimerId, TimerReadRes<u64>),
67
68    /// Sub error which occured during `read()` or any operation on timer's 
69    /// FD.
70    SubError(TimerId, TimerPortableErr)
71}
72
73impl fmt::Display for PollEventType
74{
75    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result 
76    {
77        match self
78        {
79            Self::TimerRes(timer, res) => 
80                write!(f, "timer {}, res: {}", timer, res),
81            Self::SubError(timer, err) => 
82                write!(f, "timer {}, error: {}", timer, err)
83        }
84    }
85}
86
87impl PollEventType
88{
89    /// Returns reference to error description.
90    pub 
91    fn get_err(&self) -> Option<&TimerPortableErr>
92    {
93        let Self::SubError(_, err) = self
94        else { return None };
95
96        return Some(err);
97    }
98}
99
100/// A wrapper which provides a funtionality for the [TimerPoll].
101/// 
102/// A [TimerFd] should be wrapped into this instance and a poll
103/// instance is attached during wrapping.
104/// 
105/// By calling [drop], the timer is automatically removed from the
106/// `poller` and timer will be destructed too. 
107/// The same situation happens if [SyncTimerFd::detach_timer]
108/// is called, but the timer instance is returned.
109#[derive(Debug)]
110pub struct PolledTimerFd<T: FdTimerMarker>
111{
112    /// A timer instance. This is any timer which implements
113    /// [FdTimerMarker] trait. The `Option`` is needed to overcome 
114    /// problem with `drop` and fields moving.
115    arc_timer: OnceCell<T>,
116
117    /// A [Weak] back-reference to the [DefaultEventWatch] i.e 
118    /// `poller`. Used to deregester the timer instance from
119    /// `poller`. This was intentionaly made as a weak reference
120    /// because if the poll instance will be removed, the `drop`
121    /// or other thread will be able to detect that.
122    poll_back_ref: Weak<DefaultEventWatch>
123}
124
125impl<T: FdTimerMarker> fmt::Display for PolledTimerFd<T> 
126{
127    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result 
128    {
129        write!(f, "timer: {}, poll: {}", 
130            self.arc_timer.get().unwrap(), 
131            self.poll_back_ref.upgrade().map_or("poll instance removed".into(), |f| f.to_string())
132        )
133    }
134}
135
136impl<T: FdTimerMarker> Eq for PolledTimerFd<T>  {}
137
138impl<T: FdTimerMarker> PartialEq for PolledTimerFd<T>  
139{
140    fn eq(&self, other: &Self) -> bool 
141    {
142        return self.arc_timer == other.arc_timer;
143    }
144}
145
146impl<T: FdTimerMarker> PartialEq<str> for PolledTimerFd<T>  
147{
148    fn eq(&self, other: &str) -> bool 
149    {
150        return self.arc_timer.get().map_or(false, |f| f.as_ref() == other);
151    }
152}
153
154impl<T: FdTimerMarker> AsRef<str> for PolledTimerFd<T>  
155{
156    fn as_ref(&self) -> &str 
157    {
158        return self.arc_timer.get().unwrap().as_ref().as_ref();
159    }
160}
161
162#[cfg(target_family = "unix")]
163impl<T: FdTimerMarker> Ord for PolledTimerFd<T>  
164{
165    fn cmp(&self, other: &Self) -> std::cmp::Ordering 
166    {
167        return self.arc_timer.get().unwrap().as_raw_fd().cmp(&other.arc_timer.get().unwrap().as_raw_fd());
168    }
169}
170
171#[cfg(target_family = "windows")]
172impl<T: FdTimerMarker> Ord for PolledTimerFd<T>  
173{
174    fn cmp(&self, other: &Self) -> std::cmp::Ordering 
175    {
176        return self.arc_timer.get().unwrap().as_raw_handle().cmp(&other.arc_timer.get().unwrap().as_raw_handle());
177    }
178}
179
180impl<T: FdTimerMarker> PartialOrd for PolledTimerFd <T> 
181{
182    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> 
183    {
184        return Some(self.cmp(other));
185    }
186}
187
188impl<T: FdTimerMarker> Drop for PolledTimerFd<T>  
189{
190    fn drop(&mut self) 
191    {
192        let Some(t) = self.arc_timer.take()
193        else { return };
194
195        let Some(poll_ref) = self.poll_back_ref.upgrade()
196        else { return };
197
198        // deregester
199        let _ = poll_ref.delete(&t);
200    }
201}
202
203impl<T: FdTimerMarker> PolledTimerFd<T>  
204{
205    /// Attaches timer `T` to the provided [TimerPoll] instance and regesters
206    /// the timer in the `poll` instance returning an error type in case of
207    /// any errors.
208    /// 
209    /// # Arguments
210    /// 
211    /// * `timer` - `T` a timer instance which implements [FdTimerMarker]
212    /// 
213    /// * `poll` - a [TimerPoll] to which the timer will be added.
214    /// 
215    /// # Errors
216    /// 
217    /// * [TimerErrorType::EPoll] - error generated by the EPoll, KQueue, Poll, etc
218    /// 
219    /// * [TimerErrorType::Duplicate] - a duplicate record i.e FD already presents on the list 
220    fn attached_timer(timer: T, poll: Weak<DefaultEventWatch>) -> TimerResult<Self> 
221    {
222        let once = OnceCell::new();
223        once.get_or_init(|| timer);
224
225        return Ok(
226            Self
227            {
228                arc_timer:
229                    once,
230                poll_back_ref: 
231                    poll
232            }
233        );
234    }
235
236    /// Removes the timer from the `poll` instance and releases the 
237    /// timer instance.
238    /// 
239    /// In case, if it is not possible to relese the timer, the
240    /// [Result::Err] is returnes with `Self`. Otherwise, a `T` is
241    /// returned.
242    pub 
243    fn detach_timer(mut self) -> Result<T, Self>
244    {
245        // check if there are more than 2 strong references. This 
246        // method needs improvement or disallow to clone the timer
247        // outside of crate.
248        if self.arc_timer.get().unwrap().get_strong_count() > 2
249        {
250            return Err(self);
251        }
252
253        if let Some(poll_ref) = self.poll_back_ref.upgrade()
254        {
255            let _ = poll_ref.delete(self.arc_timer.get().unwrap());
256        }
257
258
259        let timer = self.arc_timer.take().unwrap();        
260
261        return Ok(timer);
262    }
263
264    /// Checks if `poll` instance still presents. It can not verify if
265    /// `poll` operates normally. Just checks if current instance is attached to
266    /// the instance which is valid.
267    pub 
268    fn is_poll_valid(&self) -> bool
269    {
270        return self.poll_back_ref.upgrade().is_some();
271    }
272
273    /// Returns the reference to the inner timer.
274    pub 
275    fn get_inner(&self) -> &T
276    {
277        return self.arc_timer.get().unwrap();
278    }
279
280    // Returns the mutable reference to the inner timer.
281    pub 
282    fn get_inner_mut(&mut self) -> &mut T
283    {
284        return self.arc_timer.get_mut().unwrap();
285    }
286}
287
288
289/// A standart functions for each timer.
290pub trait TimerPollOps
291{
292    /// Creates new default instance.
293    /// 
294    /// # Returns
295    /// 
296    /// A [TimerResult] is returned with instance on success.
297    fn new() -> TimerResult<Self> where Self: Sized;
298
299    /// Adds the timer to the event monitor. It accepts any reference to instance which
300    /// implements [AsFd] and it is not limited specificly to timers. Maybe later this
301    /// behaviour will me modified.
302    /// 
303    /// # Arguments
304    /// 
305    /// * `timer` - TimerFd
306    /// 
307    /// # Returns
308    /// 
309    /// A [TimerResult] i.e [Result] is returned with error description in case of error.
310    fn add(&self, timer: TimerFd) -> TimerResult<()>;
311
312    /// Removes the specific timer's FD from the event monitor.
313    /// 
314    /// # Arguments
315    /// 
316    /// * `timer` - `FD` where impl [FdTimerMarker] a timer instance. 
317    /// 
318    /// # Returns
319    /// 
320    /// A [TimerResult] i.e [Result] is returned with error description in case of error.
321    fn delete<FD: FdTimerMarker>(&self, timer: &FD) -> TimerResult<()>;
322
323    /// Polls the event monitor for events. Depending on the `timeout` the behaviour will
324    /// be different.
325    /// 
326    /// 
327    /// # Arguments
328    /// 
329    /// * `timeout` - poll timeout. If set to [Option::None] will block the current thread.
330    ///     If set to [Option::Some] with inner value `0` will return immidiatly. The 
331    ///     timeout is set in `miliseconds`.
332    /// 
333    /// # Returns 
334    /// 
335    /// A [TimerResult] i.e [Result] is returned with
336    /// 
337    /// * [Result::Ok] with the [PollResult] where:
338    /// 
339    ///     * [PollResult::Some] with the [Vec] with the [RawFd] of the timer's where the event has
340    ///         happened.
341    /// 
342    ///     * [PollResult::None] if no events happened.
343    /// 
344    ///     * [PollResult::TimerRemoved] if timer was removed during polling operation. Otherwise,
345    ///         it will not be returned. If timer was cancelled and another timer times out, the 
346    ///         `TimerRemoved` will be supressed in favor of the [PollResult::Some].
347    /// 
348    /// * [Result::Err] with error description.
349    fn poll(&self, timeout: Option<i32>) -> TimerResult<Option<Vec<PollEventType>>>;
350
351    /// Returns the amount of timer's FDs
352    fn get_count(&self) -> usize;
353
354    /// Provides a [Weak] reference to the wakeup [EventFd].
355    fn get_poll_interruptor(&self) -> PollInterrupt;
356
357    /// Attempts to interrupt the poll operaiton. If successfull returns `true`.
358    fn interrupt_poll(&self) -> bool;
359}
360
361#[derive(Debug)]
362pub struct PollInterruptAq(Arc<EventFd>);
363
364impl PollInterruptAq
365{
366    pub 
367    fn interrupt(&self) -> TimerResult<()>
368    {
369        return 
370            self
371                .0
372                .write(1)
373                .map_err(|e|
374                    map_timer_err!(TimerErrorType::EPoll(e), "can not interrupt POLL!")
375                )
376                .map(|_| ());
377    }
378
379    pub 
380    fn interrupt_drop(self) -> TimerResult<()>
381    {
382        return 
383            self.interrupt();
384    }
385}
386
387// todo 
388#[derive(Debug, Clone)]
389pub struct PollInterrupt(Weak<EventFd>);
390
391impl PollInterrupt
392{
393    pub(crate)  
394    fn new(ev_weak: Weak<EventFd>) -> Self
395    {
396        return Self(ev_weak);
397    }
398
399    #[cfg(target_family = "unix")]
400    pub 
401    fn aquire(&self) -> TimerResult<PollInterruptAq>
402    {
403        return 
404            self
405                .0
406                .upgrade()
407                .ok_or_else(||
408                    map_timer_err!(TimerErrorType::EPoll(Errno::EINVAL), "timer poll has gone and not active!")
409                )
410                .map(|v| PollInterruptAq(v));
411    }
412
413    #[cfg(target_family = "windows")]
414    pub 
415    fn aquire(&self) -> TimerResult<PollInterruptAq>
416    {
417        use windows::core::Error;
418
419        return 
420            self
421                .0
422                .upgrade()
423                .ok_or_else(||
424                    map_timer_err!(TimerErrorType::EPoll(Error::empty()), "timer poll has gone and not active!")
425                )
426                .map(|v| PollInterruptAq(v));
427    }
428}
429
430/// A event notification system for timers.
431/// 
432/// This instance can be wrapped into [Arc] and `polled` in separate thread.
433/// 
434/// A timer which is added to the `poll` instance is wrapped into
435/// [PolledTimerFd].
436/// 
437/// ```ignore
438/// let poll = TimerPoll::new().unwrap();
439/// 
440/// let timer1 =
441///     TimerFd::new("test".into(), TimerType::CLOCK_REALTIME, TimerFlags::TFD_NONBLOCK)
442///     .unwrap();
443/// 
444/// let polled_timer1 = poll.add(timer1).unwrap();
445/// ```
446#[repr(transparent)]
447#[derive(Debug, Clone)]
448pub struct TimerPoll(Arc<DefaultEventWatch>);
449
450impl fmt::Display for TimerPoll
451{
452    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result 
453    {
454        write!(f, "{}", self.0.as_ref())
455    }
456}
457
458impl TimerPoll
459{
460    #[inline] 
461    fn get_timer(&self) -> &DefaultEventWatch
462    {
463        return &self.0;
464    }
465
466    /// Creates new instance of the event listener.
467    pub 
468    fn new() -> TimerResult<Self>
469    {
470        return Ok( Self( Arc::new(DefaultEventWatch::new()?) ) );
471    }
472
473    pub(super)
474    fn downgrade(&self) -> Weak<DefaultEventWatch>
475    {
476        return Arc::downgrade(&self.0);
477    }
478
479    /// Adds the timer to the event monitor. It accepts any reference to instance which
480    /// implements [AsFd] and it is not limited specificly to timers. Maybe later this
481    /// behaviour will me modified.
482    /// 
483    /// # Arguments
484    /// 
485    /// * `timer` - `T` where impl [FdTimerMarker] a timer instance. The provided
486    ///     FD will be polled for [EpollFlags::EPOLLIN] event types. 
487    ///     The FD of the timer should be inited as non-blocking, but if it is not, 
488    ///     the function attepts to switch the mode. It will not be restored when
489    ///     the timer will be removed from `Self`.
490    /// 
491    /// # Returns
492    /// 
493    /// A [TimerResult] i.e [Result] is returned with error description in case of error.
494    pub  
495    fn add<T: FdTimerMarker>(&self, timer: T) -> TimerResult<PolledTimerFd<T>>
496    {
497        let timer_fd: TimerFd = timer.clone_timer();
498
499        // check if FD is non blocking, if not set nonblocking
500        let timer_fd_status = 
501            timer_fd
502                .get_timer()
503                .is_nonblocking()
504                .map_err(|e| 
505                    map_timer_err!(TimerErrorType::TimerError(e.get_errno()), 
506                        "timer: '{}', is_nonblocking error: '{}'", timer_fd, e)
507                )?;
508
509        if timer_fd_status == false
510        {
511            // set nonblocking
512            timer_fd
513                .get_timer()
514                .set_nonblocking(true)
515                .map_err(|e| 
516                    map_timer_err!(TimerErrorType::TimerError(e.get_errno()), 
517                        "timer: '{}', set_nonblocking error: '{}'", timer_fd, e)
518                )?
519        }
520        
521        self.get_timer().add(timer.clone_timer())?;
522
523        return PolledTimerFd::attached_timer(timer, self.downgrade());
524    }
525
526    /// Polls the event monitor for events. Depending on the `timeout` the behaviour will
527    /// be different.
528    /// 
529    /// # Arguments
530    /// 
531    /// * `timeout` - poll timeout. If set to [Option::None] will block the current thread.
532    ///     If set to [Option::Some] with inner value `0` will return immidiatly. The 
533    ///     timeout is set in `miliseconds`.
534    /// 
535    /// # Returns 
536    /// 
537    /// A [TimerResult] i.e [Result] is returned with
538    /// 
539    /// * [Result::Ok] with the [Option] where:
540    /// 
541    ///     * [Option::Some] with the [Vec] with the [RawFd] of the timer's where the event has
542    ///         happened.
543    /// 
544    ///     * [Option::None] if no events happened.
545    /// 
546    /// * [Result::Err] with error description.
547    #[inline]
548    pub  
549    fn poll(&self, timeout: Option<i32>) -> TimerResult<Option<Vec<PollEventType>>>
550    {
551        return self.get_timer().poll(timeout);
552    }
553
554    /// Aquires the [PollInterrupt] which can be used to 
555    /// interrupt the `poll`.
556    #[inline]
557    pub 
558    fn get_poll_interruptor(&self) -> PollInterrupt
559    {
560        return self.get_timer().get_poll_interruptor();
561    }
562
563    /// Interrupts the `poll` if any.
564    #[inline]
565    pub 
566    fn interrupt_poll(&self) -> bool 
567    {
568        return self.get_timer().interrupt_poll();
569    }
570}
571
572
573#[cfg(test)]
574mod tests
575{
576    use std::{borrow::Cow};
577
578    use crate::{FdTimerCom, RelativeTime, TimerPoll, common, timer_portable::{AsTimerId, TimerExpMode, TimerFlags, TimerType, timer::{AbsoluteTime, TimerFd}}};
579
580    use super::*;
581
582    #[test] 
583    fn test_poller_1()
584    {
585
586        let timer1 =
587            TimerFd::new("test".into(), TimerType::CLOCK_REALTIME, TimerFlags::TFD_NONBLOCK)
588                .unwrap();
589        
590
591        let poll = TimerPoll::new().unwrap();
592
593        let polled_timer1 = poll.add(timer1).unwrap();
594
595        let tss_set = AbsoluteTime::now().add_sec(2);
596        let tss_tm = TimerExpMode::<AbsoluteTime>::new_oneshot(tss_set);
597
598        polled_timer1.get_inner().get_timer().set_time(tss_tm).unwrap();
599
600        let measure_s = AbsoluteTime::now();
601
602        let res =poll.poll(None).unwrap();
603
604        let measure_e = AbsoluteTime::now();
605
606        println!("poll took: {}", measure_e - measure_s);
607
608        assert_eq!(res.is_some(), true);
609        assert_eq!(res.as_ref().unwrap().len(), 1);
610
611        let k = &res.unwrap()[0];
612
613        let PollEventType::TimerRes(timer_id, timerres) = k
614            else { panic!("wrong type {}", k) };
615
616        assert_eq!(polled_timer1.get_inner().as_timer_id(), *timer_id);
617        assert_eq!(*timerres, crate::TimerReadRes::Ok(1));
618    }
619
620    #[test]
621    fn test_poller_2()
622    {
623        let ts = common::get_current_timestamp();
624
625        let timer1 =
626            TimerFd::new(Cow::Borrowed("test1"), TimerType::CLOCK_REALTIME, TimerFlags::TFD_NONBLOCK)
627                .unwrap();
628
629        let timer1_time =
630            TimerExpMode::<AbsoluteTime>::new_oneshot(AbsoluteTime::from(ts) + RelativeTime::new_time(2, 0));
631
632        let timer2 =
633            TimerFd::new(Cow::Borrowed("test2"), TimerType::CLOCK_REALTIME, TimerFlags::TFD_NONBLOCK)
634                .unwrap();
635
636        let timer2_time =
637            TimerExpMode::<AbsoluteTime>::new_oneshot(AbsoluteTime::from(ts) + RelativeTime::new_time(3, 0));
638
639
640
641        let poll = TimerPoll::new().unwrap();
642
643        let timer1 = poll.add(timer1).unwrap();
644        let timer2 = poll.add(timer2).unwrap();
645
646        timer1.get_inner().get_timer().set_time(timer1_time).unwrap();
647        timer2.get_inner().get_timer().set_time(timer2_time).unwrap();
648
649
650        let res = poll.poll(None).unwrap();
651
652        println!("{:?}", res);
653
654        for i in res.unwrap()
655        {
656            println!("{:?}", i);
657        }
658
659        let res = poll.poll(None);
660        assert_eq!(res.is_ok(), true);
661        println!("{:?}", res);
662
663        let res = poll.poll(Some(1000));
664        println!("{:?}", res);
665        assert_eq!(res.is_err(), false);
666        assert_eq!(res.unwrap().is_none(), true);
667
668       
669
670        drop(timer2);
671    }
672}
673
674