@@ -26,6 +26,10 @@ declare_TCFType!(CFRunLoop, CFRunLoopRef);
26
26
impl_TCFType ! ( CFRunLoop , CFRunLoopRef , CFRunLoopGetTypeID ) ;
27
27
impl_CFTypeDescription ! ( CFRunLoop ) ;
28
28
29
+ // https://github.com/servo/core-foundation-rs/issues/550
30
+ unsafe impl Send for CFRunLoop { }
31
+ unsafe impl Sync for CFRunLoop { }
32
+
29
33
#[ derive( Copy , Clone , Debug , PartialEq ) ]
30
34
pub enum CFRunLoopRunResult {
31
35
Finished = 1 ,
@@ -176,10 +180,14 @@ impl_TCFType!(CFRunLoopObserver, CFRunLoopObserverRef, CFRunLoopObserverGetTypeI
176
180
#[ cfg( test) ]
177
181
mod test {
178
182
use super :: * ;
179
- use date:: { CFDate , CFAbsoluteTime } ;
183
+ use base:: Boolean ;
184
+ use date:: { CFAbsoluteTime , CFDate } ;
180
185
use std:: mem;
181
186
use std:: os:: raw:: c_void;
187
+ use std:: ptr:: null_mut;
182
188
use std:: sync:: mpsc;
189
+ use std:: thread:: spawn;
190
+ use std:: time:: Duration ;
183
191
184
192
#[ test]
185
193
fn wait_200_milliseconds ( ) {
@@ -221,4 +229,62 @@ mod test {
221
229
let _ = unsafe { ( * info) . elapsed_tx . send ( elapsed) } ;
222
230
CFRunLoop :: get_current ( ) . stop ( ) ;
223
231
}
232
+
233
+ extern "C" fn observe ( _: CFRunLoopObserverRef , _: CFRunLoopActivity , context : * mut c_void ) {
234
+ let tx: & mpsc:: Sender < CFRunLoop > = unsafe { & * ( context as * const _ ) } ;
235
+ let _ = tx. send ( CFRunLoop :: get_current ( ) ) ;
236
+ }
237
+
238
+ extern "C" fn observe_timer_popped ( _: CFRunLoopTimerRef , _: * mut c_void ) {
239
+ panic ! ( "timer popped unexpectedly" ) ;
240
+ }
241
+
242
+ #[ test]
243
+ fn observe_runloop ( ) {
244
+ let ( tx, rx) = mpsc:: channel ( ) ;
245
+ spawn ( move || {
246
+ let mut context = CFRunLoopObserverContext {
247
+ version : 0 ,
248
+ info : & tx as * const _ as * mut c_void ,
249
+ retain : None ,
250
+ release : None ,
251
+ copyDescription : None ,
252
+ } ;
253
+
254
+ let observer = unsafe {
255
+ CFRunLoopObserver :: wrap_under_create_rule ( CFRunLoopObserverCreate (
256
+ kCFAllocatorDefault,
257
+ kCFRunLoopEntry,
258
+ false as Boolean ,
259
+ 0 ,
260
+ observe,
261
+ & mut context,
262
+ ) )
263
+ } ;
264
+
265
+ let runloop = CFRunLoop :: get_current ( ) ;
266
+ runloop. add_observer ( & observer, unsafe { kCFRunLoopDefaultMode } ) ;
267
+
268
+ let timer = CFRunLoopTimer :: new (
269
+ CFDate :: now ( ) . abs_time ( ) + 1f64 ,
270
+ 0f64 ,
271
+ 0 ,
272
+ 0 ,
273
+ observe_timer_popped,
274
+ null_mut ( ) ,
275
+ ) ;
276
+ runloop. add_timer ( & timer, unsafe { kCFRunLoopDefaultMode } ) ;
277
+
278
+ let result = unsafe {
279
+ CFRunLoop :: run_in_mode ( kCFRunLoopDefaultMode, Duration :: from_secs ( 10 ) , false )
280
+ } ;
281
+
282
+ assert_eq ! ( result, CFRunLoopRunResult :: Stopped ) ;
283
+
284
+ drop ( tx) ;
285
+ } ) ;
286
+
287
+ let runloop: CFRunLoop = rx. recv ( ) . unwrap ( ) ;
288
+ runloop. stop ( ) ;
289
+ }
224
290
}
0 commit comments