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:: check_err;
78use crate :: Result ;
89
9- use std:: sync:: { mpsc:: Sender , Arc , Mutex } ;
10+ use std:: sync:: {
11+ mpsc:: { channel, Receiver , Sender } ,
12+ Arc , Mutex ,
13+ } ;
1014use std:: { thread, thread:: JoinHandle } ;
1115
1216#[ derive( Debug , Default ) ]
@@ -20,7 +24,50 @@ pub struct Timer {
2024
2125impl Timer {
2226 pub fn initialize ( self ) -> Result < Self > {
23- Ok ( self )
27+ let txs = Arc :: clone ( & self . txs ) ;
28+
29+ // Add Default tx
30+ let ( tx, _rx) : ( Sender < u64 > , Receiver < u64 > ) = channel ( ) ;
31+ txs. lock ( ) ?. push ( tx) ;
32+
33+ let kqueue = kqueue ( ) ?;
34+
35+ let handle = Some ( thread:: spawn ( move || {
36+ // Wait for initial expiration
37+ let initial_event = Timer :: register_initial_expiration ( kqueue) ?;
38+ Timer :: wait_event ( kqueue, [ initial_event] . as_mut_ptr ( ) ) ?;
39+
40+ // Register loop event
41+ let loop_event = Timer :: register_loop_expiration ( kqueue) ?;
42+
43+ // Loop 10s
44+ loop {
45+ // Exit thread if there are no listeners
46+ if txs. lock ( ) ?. len ( ) == 0 {
47+ // TODO: should close file descriptors?
48+ return Ok ( ( ) ) ;
49+ }
50+
51+ // Get current time
52+ let current = std:: time:: SystemTime :: now ( )
53+ . duration_since ( std:: time:: UNIX_EPOCH ) ?
54+ . as_secs ( ) ;
55+
56+ // Iterate through Senders
57+ txs. lock ( ) ?. iter ( ) . for_each ( |tx| {
58+ // Send event to attached Sender
59+ match tx. send ( current) {
60+ Ok ( _) => { }
61+ Err ( _) => { }
62+ }
63+ } ) ;
64+
65+ // Wait 10s
66+ Timer :: wait_event ( kqueue, [ loop_event] . as_mut_ptr ( ) ) ?;
67+ }
68+ } ) ) ;
69+
70+ Ok ( Self { handle, ..self } )
2471 }
2572
2673 /// Attach an mpsc::Sender to Timer
@@ -42,4 +89,74 @@ impl Timer {
4289
4390 Ok ( ( ) )
4491 }
92+
93+ fn wait_event ( kqueue : i32 , events : * mut libc:: kevent ) -> Result < ( ) > {
94+ kevent ( kqueue, [ ] . as_mut_ptr ( ) , 0 , events, 1 , std:: ptr:: null ( ) ) ?;
95+ Ok ( ( ) )
96+ }
97+ fn register_initial_expiration ( kqueue : i32 ) -> Result < libc:: kevent > {
98+ // Get the next event time
99+ let now = std:: time:: SystemTime :: now ( )
100+ . duration_since ( std:: time:: UNIX_EPOCH ) ?
101+ . as_secs ( ) ;
102+ let rem = 10u64 . checked_sub ( now. checked_rem ( 10 ) . unwrap ( ) ) . unwrap ( ) ;
103+ let first_fire = now + rem;
104+
105+ let initial_event = libc:: kevent {
106+ ident : 1 ,
107+ filter : libc:: EVFILT_TIMER ,
108+ flags : libc:: EV_ADD | libc:: EV_ENABLE | libc:: EV_ONESHOT ,
109+ fflags : libc:: NOTE_ABSOLUTE | libc:: NOTE_SECONDS ,
110+ data : first_fire as isize ,
111+ udata : 0 as * mut libc:: c_void ,
112+ } ;
113+
114+ // add first event
115+ kevent (
116+ kqueue,
117+ [ initial_event] . as_ptr ( ) as * const libc:: kevent ,
118+ 1 ,
119+ [ ] . as_mut_ptr ( ) ,
120+ 0 ,
121+ std:: ptr:: null ( ) ,
122+ ) ?;
123+
124+ Ok ( initial_event)
125+ }
126+ fn register_loop_expiration ( kqueue : i32 ) -> Result < libc:: kevent > {
127+ let loop_event = libc:: kevent {
128+ ident : 1 ,
129+ filter : libc:: EVFILT_TIMER ,
130+ flags : libc:: EV_ADD | libc:: EV_ENABLE ,
131+ fflags : 0 ,
132+ data : 10000 ,
133+ udata : 0 as * mut libc:: c_void ,
134+ } ;
135+
136+ // add loop event
137+ let ke = kevent (
138+ kqueue,
139+ [ loop_event] . as_ptr ( ) as * const libc:: kevent ,
140+ 1 ,
141+ [ ] . as_mut_ptr ( ) ,
142+ 0 ,
143+ std:: ptr:: null ( ) ,
144+ ) ?;
145+
146+ Ok ( loop_event)
147+ }
148+ }
149+
150+ /// libc::kqueue wrapper
151+ fn kqueue ( ) -> Result < i32 > {
152+ check_err ( unsafe { libc:: kqueue ( ) } ) . map ( |kq| kq as i32 )
153+ }
154+
155+ /// libc::kevent wrapper
156+ fn kevent (
157+ kqueue : i32 , change : * const libc:: kevent , c_count : libc:: c_int , events : * mut libc:: kevent ,
158+ e_count : libc:: c_int , timeout : * const libc:: timespec ,
159+ ) -> Result < ( ) > {
160+ check_err ( unsafe { libc:: kevent ( kqueue, change, c_count, events, e_count, timeout) } ) ?;
161+ Ok ( ( ) )
45162}
0 commit comments