44// https://www.apache.org/licenses/LICENSE-2.0>. This file may not be copied, modified, or distributed
55// except according to those terms.
66
7+ use crate :: utils:: { epoll_create1, epoll_ctl, epoll_wait, read, timerfd_create, timerfd_settime} ;
78use crate :: Result ;
89
910use std:: sync:: { mpsc:: Sender , Arc , Mutex } ;
@@ -19,8 +20,122 @@ pub struct Timer {
1920}
2021
2122impl Timer {
22- pub fn initialize ( self ) -> Self {
23- self
23+ pub fn initialize ( self ) -> Result < Self > {
24+ let txs = Arc :: clone ( & self . txs ) ;
25+
26+ let timer_fd = Timer :: set_timerfd ( ) ?;
27+ let epoll_fd = Timer :: create_epollfd ( timer_fd) ?;
28+
29+ let handle = Some ( thread:: spawn ( move || {
30+ loop {
31+ // Exit thread if there are no listeners
32+ if txs. lock ( ) ?. len ( ) == 0 {
33+ // TODO: should close file descriptors?
34+ return Ok ( ( ) ) ;
35+ }
36+
37+ // Fire @ 10th sec
38+ Timer :: epoll_wait ( timer_fd, epoll_fd) ?;
39+
40+ // Get current time
41+ let current = std:: time:: SystemTime :: now ( )
42+ . duration_since ( std:: time:: UNIX_EPOCH ) ?
43+ . as_secs ( ) ;
44+
45+ // Iterate through Senders
46+ txs. lock ( ) ?. iter ( ) . for_each ( |tx| {
47+ // Send event to attached Sender
48+ tx. send ( current) . unwrap ( ) ;
49+ } ) ;
50+ }
51+ } ) ) ;
52+
53+ Ok ( Self { handle, ..self } )
54+ }
55+
56+ /// create and set a timer file descriptor
57+ fn set_timerfd ( ) -> Result < libc:: c_int > {
58+ // Set the timer to use the system time.
59+ let clockid: libc:: clockid_t = libc:: CLOCK_REALTIME ;
60+ // Non-blocking file descriptor
61+ let clock_flags: libc:: c_int = libc:: TFD_NONBLOCK ;
62+
63+ // Create timer fd
64+ let tfd = timerfd_create ( clockid, clock_flags) ?;
65+
66+ // Get the next event time
67+ let now = std:: time:: SystemTime :: now ( )
68+ . duration_since ( std:: time:: UNIX_EPOCH ) ?
69+ . as_secs ( ) ;
70+ let rem = 10u64 . checked_sub ( now. checked_rem ( 10 ) . unwrap ( ) ) . unwrap ( ) ;
71+ let first_fire = now + rem;
72+
73+ // new_value sets the Timer
74+ let mut new_value = libc:: itimerspec {
75+ it_interval : libc:: timespec {
76+ tv_sec : 10 ,
77+ tv_nsec : 0 ,
78+ } ,
79+ it_value : libc:: timespec {
80+ tv_sec : first_fire as i64 ,
81+ tv_nsec : 0 ,
82+ } ,
83+ } ;
84+
85+ // Empty itimerspec object
86+ let mut old_value = libc:: itimerspec {
87+ it_interval : libc:: timespec {
88+ tv_sec : 0 ,
89+ tv_nsec : 0 ,
90+ } ,
91+ it_value : libc:: timespec {
92+ tv_sec : 0 ,
93+ tv_nsec : 0 ,
94+ } ,
95+ } ;
96+
97+ let set_flags = libc:: TFD_TIMER_ABSTIME ;
98+
99+ // Set the timer
100+ timerfd_settime ( tfd, set_flags, & mut new_value, & mut old_value) ?;
101+
102+ // Return file descriptor
103+ Ok ( tfd)
104+ }
105+
106+ /// Create a new epoll file descriptor and add the timer to its interests
107+ fn create_epollfd ( timer_fd : libc:: c_int ) -> Result < libc:: c_int > {
108+ // create a new epoll fd
109+ let epoll_fd = epoll_create1 ( 0 ) ?;
110+
111+ // event to pull
112+ let mut event = libc:: epoll_event {
113+ events : libc:: EPOLLIN as u32 ,
114+ u64 : 1 ,
115+ } ;
116+
117+ let epoll_flags = libc:: EPOLL_CTL_ADD ;
118+
119+ // add event to the epoll
120+ epoll_ctl ( epoll_fd, epoll_flags, timer_fd, & mut event) ?;
121+
122+ // return epoll fd
123+ Ok ( epoll_fd)
124+ }
125+
126+ fn epoll_wait ( timer_fd : libc:: c_int , epoll_fd : libc:: c_int ) -> Result < ( ) > {
127+ // vector to store events
128+ let mut events = Vec :: with_capacity ( 1 ) ;
129+
130+ // wait for the timer to fire an event. This is function will block.
131+ epoll_wait ( epoll_fd, events. as_mut_ptr ( ) , 1 , -1 ) ?;
132+
133+ // read the value from the timerfd. This is required to re-arm the timer.
134+ let mut buffer: u64 = 0 ;
135+ let bufptr: * mut _ = & mut buffer;
136+ read ( timer_fd, bufptr as * mut libc:: c_void , 8 ) ?;
137+
138+ Ok ( ( ) )
24139 }
25140
26141 /// Attach an mpsc::Sender to Timer
0 commit comments