From a1df3385f7094268c1c348849d283c04ce62da95 Mon Sep 17 00:00:00 2001 From: Michael Farrell Date: Tue, 4 Jul 2023 16:47:05 +1000 Subject: [PATCH] mark CFRunLoop as Send+Sync, and test it --- core-foundation/src/runloop.rs | 68 +++++++++++++++++++++++++++++++++- 1 file changed, 67 insertions(+), 1 deletion(-) diff --git a/core-foundation/src/runloop.rs b/core-foundation/src/runloop.rs index be06f4ec7..fd1954d5f 100644 --- a/core-foundation/src/runloop.rs +++ b/core-foundation/src/runloop.rs @@ -26,6 +26,10 @@ declare_TCFType!(CFRunLoop, CFRunLoopRef); impl_TCFType!(CFRunLoop, CFRunLoopRef, CFRunLoopGetTypeID); impl_CFTypeDescription!(CFRunLoop); +// https://github.com/servo/core-foundation-rs/issues/550 +unsafe impl Send for CFRunLoop {} +unsafe impl Sync for CFRunLoop {} + #[derive(Copy, Clone, Debug, PartialEq)] pub enum CFRunLoopRunResult { Finished = 1, @@ -176,10 +180,14 @@ impl_TCFType!(CFRunLoopObserver, CFRunLoopObserverRef, CFRunLoopObserverGetTypeI #[cfg(test)] mod test { use super::*; - use date::{CFDate, CFAbsoluteTime}; + use base::Boolean; + use date::{CFAbsoluteTime, CFDate}; use std::mem; use std::os::raw::c_void; + use std::ptr::null_mut; use std::sync::mpsc; + use std::thread::spawn; + use std::time::Duration; #[test] fn wait_200_milliseconds() { @@ -221,4 +229,62 @@ mod test { let _ = unsafe { (*info).elapsed_tx.send(elapsed) }; CFRunLoop::get_current().stop(); } + + extern "C" fn observe(_: CFRunLoopObserverRef, _: CFRunLoopActivity, context: *mut c_void) { + let tx: &mpsc::Sender = unsafe { &*(context as *const _) }; + let _ = tx.send(CFRunLoop::get_current()); + } + + extern "C" fn observe_timer_popped(_: CFRunLoopTimerRef, _: *mut c_void) { + panic!("timer popped unexpectedly"); + } + + #[test] + fn observe_runloop() { + let (tx, rx) = mpsc::channel(); + spawn(move || { + let mut context = CFRunLoopObserverContext { + version: 0, + info: &tx as *const _ as *mut c_void, + retain: None, + release: None, + copyDescription: None, + }; + + let observer = unsafe { + CFRunLoopObserver::wrap_under_create_rule(CFRunLoopObserverCreate( + kCFAllocatorDefault, + kCFRunLoopEntry, + false as Boolean, + 0, + observe, + &mut context, + )) + }; + + let runloop = CFRunLoop::get_current(); + runloop.add_observer(&observer, unsafe { kCFRunLoopDefaultMode }); + + let timer = CFRunLoopTimer::new( + CFDate::now().abs_time() + 1f64, + 0f64, + 0, + 0, + observe_timer_popped, + null_mut(), + ); + runloop.add_timer(&timer, unsafe { kCFRunLoopDefaultMode }); + + let result = unsafe { + CFRunLoop::run_in_mode(kCFRunLoopDefaultMode, Duration::from_secs(10), false) + }; + + assert_eq!(result, CFRunLoopRunResult::Stopped); + + drop(tx); + }); + + let runloop: CFRunLoop = rx.recv().unwrap(); + runloop.stop(); + } }