@@ -86,26 +86,50 @@ impl<Scope: WorkScope> TimerState<Scope> {
86
86
pub fn get_timer_period ( & self ) -> Result < Duration , RclrsError > {
87
87
let mut timer_period_ns = 0 ;
88
88
unsafe {
89
+ // SAFETY: The unwrap is safe here since we never use the rcl_timer
90
+ // in a way that could panic while the mutex is locked.
89
91
let rcl_timer = self . handle . rcl_timer . lock ( ) . unwrap ( ) ;
92
+
93
+ // SAFETY: The rcl_timer is kept valid by the TimerState. This C
94
+ // function call is thread-safe and only requires a valid rcl_timer
95
+ // to be passed in.
90
96
rcl_timer_get_period ( & * rcl_timer, & mut timer_period_ns)
91
97
}
92
98
. ok ( ) ?;
93
99
94
100
rcl_duration ( timer_period_ns)
95
101
}
96
102
97
- /// Cancels the timer, stopping the execution of the callback
103
+ /// Cancels the timer, stopping the execution of the callback.
104
+ ///
105
+ /// [`TimerState::is_ready`] will always return false while the timer is in
106
+ /// a cancelled state. [`TimerState::reset`] can be used to revert the timer
107
+ /// out of the cancelled state.
98
108
pub fn cancel ( & self ) -> Result < ( ) , RclrsError > {
99
- let mut rcl_timer = self . handle . rcl_timer . lock ( ) . unwrap ( ) ;
100
- let cancel_result = unsafe { rcl_timer_cancel ( & mut * rcl_timer) } . ok ( ) ?;
109
+ let cancel_result = unsafe {
110
+ // SAFETY: The unwrap is safe here since we never use the rcl_timer
111
+ // in a way that could panic while the mutex is locked.
112
+ let mut rcl_timer = self . handle . rcl_timer . lock ( ) . unwrap ( ) ;
113
+
114
+ // SAFETY: The rcl_timer is kept valid by the TimerState. This C
115
+ // function call is thread-safe and only requires a valid rcl_timer
116
+ // to be passed in.
117
+ rcl_timer_cancel ( & mut * rcl_timer)
118
+ } . ok ( ) ?;
101
119
Ok ( cancel_result)
102
120
}
103
121
104
122
/// Checks whether the timer is canceled or not
105
123
pub fn is_canceled ( & self ) -> Result < bool , RclrsError > {
106
124
let mut is_canceled = false ;
107
125
unsafe {
126
+ // SAFETY: The unwrap is safe here since we never use the rcl_timer
127
+ // in a way that could panic while the mutex is locked.
108
128
let rcl_timer = self . handle . rcl_timer . lock ( ) . unwrap ( ) ;
129
+
130
+ // SAFETY: The rcl_timer is kept valid by the TimerState. This C
131
+ // function call is thread-safe and only requires a valid rcl_timer
132
+ // to be passed in.
109
133
rcl_timer_is_canceled ( & * rcl_timer, & mut is_canceled)
110
134
}
111
135
. ok ( ) ?;
@@ -128,7 +152,13 @@ impl<Scope: WorkScope> TimerState<Scope> {
128
152
pub fn time_since_last_call ( & self ) -> Result < Duration , RclrsError > {
129
153
let mut time_value_ns: i64 = 0 ;
130
154
unsafe {
155
+ // SAFETY: The unwrap is safe here since we never use the rcl_timer
156
+ // in a way that could panic while the mutex is locked.
131
157
let rcl_timer = self . handle . rcl_timer . lock ( ) . unwrap ( ) ;
158
+
159
+ // SAFETY: The rcl_timer is kept valid by the TimerState. This C
160
+ // function call is thread-safe and only requires a valid rcl_timer
161
+ // to be passed in.
132
162
rcl_timer_get_time_since_last_call ( & * rcl_timer, & mut time_value_ns)
133
163
}
134
164
. ok ( ) ?;
@@ -140,7 +170,13 @@ impl<Scope: WorkScope> TimerState<Scope> {
140
170
pub fn time_until_next_call ( & self ) -> Result < Duration , RclrsError > {
141
171
let mut time_value_ns: i64 = 0 ;
142
172
unsafe {
173
+ // SAFETY: The unwrap is safe here since we never use the rcl_timer
174
+ // in a way that could panic while the mutex is locked.
143
175
let rcl_timer = self . handle . rcl_timer . lock ( ) . unwrap ( ) ;
176
+
177
+ // SAFETY: The rcl_timer is kept valid by the TimerState. This C
178
+ // function call is thread-safe and only requires a valid rcl_timer
179
+ // to be passed in.
144
180
rcl_timer_get_time_until_next_call ( & * rcl_timer, & mut time_value_ns)
145
181
}
146
182
. ok ( ) ?;
@@ -149,9 +185,20 @@ impl<Scope: WorkScope> TimerState<Scope> {
149
185
}
150
186
151
187
/// Resets the timer.
188
+ ///
189
+ /// For all timers it will reset the last call time to now. For cancelled
190
+ /// timers it will revert the timer to no longer being cancelled.
152
191
pub fn reset ( & self ) -> Result < ( ) , RclrsError > {
192
+ // SAFETY: The unwrap is safe here since we never use the rcl_timer
193
+ // in a way that could panic while the mutex is locked.
153
194
let mut rcl_timer = self . handle . rcl_timer . lock ( ) . unwrap ( ) ;
154
- unsafe { rcl_timer_reset ( & mut * rcl_timer) } . ok ( )
195
+
196
+ unsafe {
197
+ // SAFETY: The rcl_timer is kept valid by the TimerState. This C
198
+ // function call is thread-safe and only requires a valid rcl_timer
199
+ // to be passed in.
200
+ rcl_timer_reset ( & mut * rcl_timer)
201
+ } . ok ( )
155
202
}
156
203
157
204
/// Checks if the timer is ready (not canceled)
@@ -215,8 +262,10 @@ impl<Scope: WorkScope> TimerState<Scope> {
215
262
let rcl_timer_callback: rcl_timer_callback_t = None ;
216
263
217
264
let rcl_timer = Arc :: new ( Mutex :: new (
218
- // SAFETY: Zero-initializing a timer is always safe
219
- unsafe { rcl_get_zero_initialized_timer ( ) } ,
265
+ unsafe {
266
+ // SAFETY: Zero-initializing a timer is always safe
267
+ rcl_get_zero_initialized_timer ( )
268
+ } ,
220
269
) ) ;
221
270
222
271
unsafe {
@@ -340,8 +389,16 @@ impl<Scope: WorkScope> TimerState<Scope> {
340
389
/// in the [`Timer`] struct. This means there are no side-effects to this
341
390
/// except to keep track of when the timer has been called.
342
391
fn rcl_call ( & self ) -> Result < ( ) , RclrsError > {
392
+ // SAFETY: The unwrap is safe here since we never use the rcl_timer
393
+ // in a way that could panic while the mutex is locked.
343
394
let mut rcl_timer = self . handle . rcl_timer . lock ( ) . unwrap ( ) ;
344
- unsafe { rcl_timer_call ( & mut * rcl_timer) } . ok ( )
395
+
396
+ unsafe {
397
+ // SAFETY: The rcl_timer is kept valid by the TimerState. This C
398
+ // function call is thread-safe and only requires a valid rcl_timer
399
+ // to be passed in.
400
+ rcl_timer_call ( & mut * rcl_timer)
401
+ } . ok ( )
345
402
}
346
403
347
404
/// Used by [`Timer::execute`] to restore the state of the callback if and
@@ -469,15 +526,17 @@ pub(crate) struct TimerHandle {
469
526
impl Drop for TimerHandle {
470
527
fn drop ( & mut self ) {
471
528
let _lifecycle = ENTITY_LIFECYCLE_MUTEX . lock ( ) . unwrap ( ) ;
472
- // SAFETY: The lifecycle mutex is locked and the clock for the timer
473
- // must still be valid because TimerHandle keeps it alive.
474
- unsafe { rcl_timer_fini ( & mut * self . rcl_timer . lock ( ) . unwrap ( ) ) } ;
529
+ unsafe {
530
+ // SAFETY: The lifecycle mutex is locked and the clock for the timer
531
+ // must still be valid because TimerHandle keeps it alive.
532
+ rcl_timer_fini ( & mut * self . rcl_timer . lock ( ) . unwrap ( ) )
533
+ } ;
475
534
}
476
535
}
477
536
478
537
// SAFETY: The functions accessing this type, including drop(), shouldn't care about the thread
479
538
// they are running in. Therefore, this type can be safely sent to another thread.
480
- unsafe impl Send for rcl_timer_t { }
539
+ impl Send for rcl_timer_t { }
481
540
482
541
#[ cfg( test) ]
483
542
mod tests {
@@ -759,8 +818,8 @@ mod tests {
759
818
handle : Arc :: clone ( & timer. handle ) ,
760
819
} ;
761
820
762
- // SAFETY: Node timers expect a payload of ()
763
821
unsafe {
822
+ // SAFETY: Node timers expect a payload of ()
764
823
executable. execute ( & mut ( ) ) . unwrap ( ) ;
765
824
}
766
825
assert ! ( !executed. load( Ordering :: Acquire ) ) ;
@@ -790,8 +849,8 @@ mod tests {
790
849
791
850
thread:: sleep ( Duration :: from_millis ( 2 ) ) ;
792
851
793
- // SAFETY: Node timers expect a payload of ()
794
852
unsafe {
853
+ // SAFETY: Node timers expect a payload of ()
795
854
executable. execute ( & mut ( ) ) . unwrap ( ) ;
796
855
}
797
856
assert ! ( executed. load( Ordering :: Acquire ) ) ;
0 commit comments