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}