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