diff --git a/.changes/wkwebview-race-condition.md b/.changes/wkwebview-race-condition.md new file mode 100644 index 000000000..8035f743b --- /dev/null +++ b/.changes/wkwebview-race-condition.md @@ -0,0 +1,6 @@ +--- +wry: minor +--- + +Fix a bug in the wkwebview implementation that could cause hangs and crashes +when wait_for_blocking_operation() was called multiple times in quick succession. \ No newline at end of file diff --git a/src/wkwebview/mod.rs b/src/wkwebview/mod.rs index b80bae84c..2a318b176 100644 --- a/src/wkwebview/mod.rs +++ b/src/wkwebview/mod.rs @@ -78,7 +78,7 @@ use std::{ panic::AssertUnwindSafe, ptr::{null_mut, NonNull}, str::{self, FromStr}, - sync::{Arc, Mutex}, + sync::{Arc, Mutex}, thread, time::Duration, }; #[cfg(feature = "mac-proxy")] @@ -1054,6 +1054,7 @@ unsafe fn window_position(view: &NSView, x: i32, y: i32, height: f64) -> CGPoint CGPoint::new(x as f64, frame.size.height - y as f64 - height) } +/// Wait synchronously for the NSRunLoop to run until a receiver has a message. unsafe fn wait_for_blocking_operation(rx: std::sync::mpsc::Receiver) -> Result { let interval = 0.0002; let limit = 1.; @@ -1061,9 +1062,16 @@ unsafe fn wait_for_blocking_operation(rx: std::sync::mpsc::Receiver) -> Re // run event loop until we get the response back, blocking for at most 3 seconds loop { let rl = objc2_foundation::NSRunLoop::mainRunLoop(); - let d = NSDate::dateWithTimeIntervalSinceNow(interval); - rl.runUntilDate(&d); + let limit_date = NSDate::dateWithTimeIntervalSinceNow(interval); + + let mode = NSString::from_str("NSDefaultRunLoopMode"); + rl.acceptInputForMode_beforeDate(&mode, &limit_date); + thread::sleep(Duration::from_secs_f64(interval)); + if let Ok(response) = rx.try_recv() { + // Extra 1ms just to make sure our runloop is cleared. + // See https://github.com/tauri-apps/wry/pull/1486 for a writeup of why this was added. + thread::sleep(Duration::from_millis(1)); return Ok(response); } elapsed += interval;