From c290e60af1f4e94f1b83aa3539a6dca09169e2c5 Mon Sep 17 00:00:00 2001 From: Logan McNaughton <848146+loganmc10@users.noreply.github.com> Date: Tue, 16 Jun 2026 11:33:27 +0200 Subject: [PATCH] put tokio runtime in dedicated thread (#1086) * put tokio runtime in dedicated thread * more * more * more * more --- Cargo.toml | 2 +- src/lib.rs | 24 +++++++++++++++++++----- src/main.rs | 10 +++++++--- src/retroachievements.rs | 5 ++--- src/ui/android.rs | 9 +++++++-- 5 files changed, 36 insertions(+), 14 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 4d6a18e5..1a752bd1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,7 +19,7 @@ serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" serde-big-array = "0.5" sha2 = "0.11" -tokio = {version = "1.46", features = ["rt-multi-thread", "macros", "fs", "process"] } +tokio = {version = "1.46", features = ["rt-multi-thread", "fs", "process"] } spin_sleep = "1.3" encoding_rs = "0.8" mimalloc = "0.1" diff --git a/src/lib.rs b/src/lib.rs index a3612624..93056efe 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -104,6 +104,19 @@ fn set_app_id() { } } +pub fn create_runtime() -> (tokio::sync::oneshot::Sender<()>, tokio::runtime::Handle) { + let (tx, rx) = std::sync::mpsc::channel(); + let (close_tx, close_rx) = tokio::sync::oneshot::channel::<()>(); + + std::thread::spawn(move || { + let rt = tokio::runtime::Runtime::new().expect("Failed to build runtime"); + tx.send(rt.handle().clone()).unwrap(); + rt.block_on(close_rx).unwrap(); + }); + + (close_tx, rx.recv().unwrap()) +} + pub fn run(args: Args, arg_count: usize) -> std::io::Result<()> { let dirs = ui::get_dirs(); @@ -213,9 +226,7 @@ pub fn run(args: Args, arg_count: usize) -> std::io::Result<()> { tx.send(false).unwrap(); } - tokio::task::block_in_place(move || { - rx.blocking_recv().unwrap(); - }); + rx.blocking_recv().unwrap(); ra_config } else { @@ -334,8 +345,10 @@ pub fn run(args: Args, arg_count: usize) -> std::io::Result<()> { #[cfg(target_os = "android")] #[unsafe(no_mangle)] -#[tokio::main] -async fn android_main(app: slint::android::AndroidApp) { +fn android_main(app: slint::android::AndroidApp) { + let (close_tx, handle) = create_runtime(); + let _guard = handle.enter(); + slint::android::init_with_event_listener(app.clone(), move |event| match event { slint::android::android_activity::PollEvent::Main(main_event) => match main_event { slint::android::android_activity::MainEvent::TerminateWindow { .. } => { @@ -368,6 +381,7 @@ async fn android_main(app: slint::android::AndroidApp) { std::fs::create_dir_all(dirs.data_dir.join("states")).unwrap(); ui::gui::app_window(&app_window, true); + close_tx.send(()).unwrap(); *android::WEAK_SLINT_WINDOW.lock().unwrap() = None; *android::ANDROID_APP.lock().unwrap() = None; } diff --git a/src/main.rs b/src/main.rs index 3a3e5222..42f400d7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,8 +5,12 @@ static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc; use clap::Parser; -#[tokio::main] -async fn main() -> std::io::Result<()> { +fn main() -> std::io::Result<()> { + let (close_tx, handle) = gopher64::create_runtime(); + let _guard = handle.enter(); + let args = gopher64::Args::parse(); - gopher64::run(args, std::env::args().count()) + let result = gopher64::run(args, std::env::args().count()); + close_tx.send(()).unwrap(); + result } diff --git a/src/retroachievements.rs b/src/retroachievements.rs index ee81cbf6..5186b284 100644 --- a/src/retroachievements.rs +++ b/src/retroachievements.rs @@ -150,9 +150,8 @@ pub fn load_game( let tx_ptr = Box::into_raw(Box::new(tx)) as *mut std::ffi::c_void; ra_load_game(rom.as_ptr(), rom_size, tx_ptr); }; - tokio::task::block_in_place(move || { - rx.blocking_recv().unwrap(); - }); + + rx.blocking_recv().unwrap(); let mut c_title = std::ptr::null(); let mut c_image_url = std::ptr::null(); diff --git a/src/ui/android.rs b/src/ui/android.rs index e16803ed..d0efa29a 100644 --- a/src/ui/android.rs +++ b/src/ui/android.rs @@ -1,4 +1,5 @@ use crate::Args; +use crate::create_runtime; use crate::run; use crate::ui; use clap::Parser; @@ -158,17 +159,21 @@ fn argv_to_strings(argc: std::ffi::c_int, argv: *mut *mut std::ffi::c_char) -> V } #[unsafe(no_mangle)] -#[tokio::main] -pub async extern "C" fn gopher64_sdl_main( +pub extern "C" fn gopher64_sdl_main( argc: std::ffi::c_int, argv: *mut *mut std::ffi::c_char, ) -> std::ffi::c_int { + let (close_tx, handle) = create_runtime(); + let _guard = handle.enter(); + let raw = argv_to_strings(argc, argv); let args = Args::try_parse_from(raw).unwrap(); if let Err(err) = run(args, argc as usize) { + close_tx.send(()).unwrap(); eprintln!("Error running game: {err:?}"); return 1; } + close_tx.send(()).unwrap(); 0 }