1- // Copyright 2021 Developers of Pyroscope.
2-
3- // Licensed under the Apache License, Version 2.0 <LICENSE or
4- // https://www.apache.org/licenses/LICENSE-2.0>. This file may not be copied, modified, or distributed
5- // except according to those terms.
6-
1+ use super :: TimerSignal ;
72use crate :: utils:: check_err;
83use crate :: utils:: get_time_range;
4+ use crate :: PyroscopeError ;
95use crate :: Result ;
106
117use std:: sync:: {
12- mpsc:: { channel, Receiver , Sender } ,
8+ mpsc:: { channel, Sender } ,
139 Arc , Mutex ,
1410} ;
15- use std:: { thread, thread:: JoinHandle } ;
11+ use std:: {
12+ thread:: { self , JoinHandle } ,
13+ time:: Duration ,
14+ } ;
1615
1716/// A thread that sends a notification every 10th second
1817///
@@ -22,57 +21,59 @@ use std::{thread, thread::JoinHandle};
2221/// The Timer thread will run continously until all Senders are dropped.
2322/// The Timer thread will be joined when all Senders are dropped.
2423
25- #[ derive( Debug , Default ) ]
24+ #[ derive( Debug ) ]
2625pub struct Timer {
2726 /// A vector to store listeners (mpsc::Sender)
28- txs : Arc < Mutex < Vec < Sender < u64 > > > > ,
27+ txs : Arc < Mutex < Vec < Sender < TimerSignal > > > > ,
2928
3029 /// Thread handle
3130 pub handle : Option < JoinHandle < Result < ( ) > > > ,
3231}
3332
3433impl Timer {
3534 /// Initialize Timer and run a thread to send events to attached listeners
36- pub fn initialize ( self ) -> Result < Self > {
37- let txs = Arc :: clone ( & self . txs ) ;
35+ pub fn initialize ( cycle : Duration ) -> Result < Self > {
36+ let txs = Arc :: new ( Mutex :: new ( Vec :: new ( ) ) ) ;
3837
39- // Add Default tx
40- let ( tx, _rx) : ( Sender < u64 > , Receiver < u64 > ) = channel ( ) ;
38+ // Add a dummy tx so the below thread does not terminate early
39+ let ( tx, _rx) = channel ( ) ;
4140 txs. lock ( ) ?. push ( tx) ;
4241
43- let timer_fd = Timer :: set_timerfd ( ) ?;
42+ let timer_fd = Timer :: set_timerfd ( cycle ) ?;
4443 let epoll_fd = Timer :: create_epollfd ( timer_fd) ?;
4544
46- let handle = Some ( thread:: spawn ( move || {
47- loop {
48- // Exit thread if there are no listeners
49- if txs. lock ( ) ?. len ( ) == 0 {
50- // Close file descriptors
51- unsafe { libc:: close ( timer_fd) } ;
52- unsafe { libc:: close ( epoll_fd) } ;
53-
54- return Ok ( ( ) ) ;
45+ let handle = Some ( {
46+ let txs = txs. clone ( ) ;
47+ thread:: spawn ( move || {
48+ loop {
49+ // Exit thread if there are no listeners
50+ if txs. lock ( ) ?. is_empty ( ) {
51+ // Close file descriptors
52+ unsafe { libc:: close ( timer_fd) } ;
53+ unsafe { libc:: close ( epoll_fd) } ;
54+ return Ok :: < _ , PyroscopeError > ( ( ) ) ;
55+ }
56+
57+ // Fire @ 10th sec
58+ Timer :: epoll_wait ( timer_fd, epoll_fd) ?;
59+
60+ // Get the current time range
61+ let from = TimerSignal :: NextSnapshot ( get_time_range ( 0 ) ?. from ) ;
62+
63+ // Iterate through Senders
64+ txs. lock ( ) ?. iter ( ) . for_each ( |tx| {
65+ // Send event to attached Sender
66+ if tx. send ( from) . is_ok ( ) { }
67+ } ) ;
5568 }
69+ } )
70+ } ) ;
5671
57- // Fire @ 10th sec
58- Timer :: epoll_wait ( timer_fd, epoll_fd) ?;
59-
60- // Get the current time range
61- let from = get_time_range ( 0 ) ?. from ;
62-
63- // Iterate through Senders
64- txs. lock ( ) ?. iter ( ) . for_each ( |tx| {
65- // Send event to attached Sender
66- if tx. send ( from) . is_ok ( ) { }
67- } ) ;
68- }
69- } ) ) ;
70-
71- Ok ( Self { handle, ..self } )
72+ Ok ( Self { handle, txs } )
7273 }
7374
7475 /// create and set a timer file descriptor
75- fn set_timerfd ( ) -> Result < libc:: c_int > {
76+ fn set_timerfd ( cycle : Duration ) -> Result < libc:: c_int > {
7677 // Set the timer to use the system time.
7778 let clockid: libc:: clockid_t = libc:: CLOCK_REALTIME ;
7879 // Non-blocking file descriptor
@@ -87,8 +88,8 @@ impl Timer {
8788 // new_value sets the Timer
8889 let mut new_value = libc:: itimerspec {
8990 it_interval : libc:: timespec {
90- tv_sec : 10 ,
91- tv_nsec : 0 ,
91+ tv_sec : cycle . as_secs ( ) as i64 ,
92+ tv_nsec : cycle . subsec_nanos ( ) as i64 ,
9293 } ,
9394 it_value : libc:: timespec {
9495 tv_sec : first_fire as i64 ,
@@ -161,7 +162,7 @@ impl Timer {
161162 ///
162163 /// Timer will dispatch an event with the timestamp of the current instant,
163164 /// every 10th second to all attached senders
164- pub fn attach_listener ( & mut self , tx : Sender < u64 > ) -> Result < ( ) > {
165+ pub fn attach_listener ( & mut self , tx : Sender < TimerSignal > ) -> Result < ( ) > {
165166 // Push Sender to a Vector of Sender(s)
166167 let txs = Arc :: clone ( & self . txs ) ;
167168 txs. lock ( ) ?. push ( tx) ;
0 commit comments