From dee2b85daa8159fa6c0258808ddb9a328c3de41b Mon Sep 17 00:00:00 2001 From: Logan McNaughton <848146+loganmc10@users.noreply.github.com> Date: Tue, 23 Jun 2026 12:27:15 +0200 Subject: [PATCH] use tokio mutex (#1112) * use tokio mutex * more --- src/device.rs | 2 +- src/lib.rs | 16 ++++----- src/savestates.rs | 87 +++++++++++++++++++---------------------------- src/ui/android.rs | 63 +++++++++++----------------------- 4 files changed, 62 insertions(+), 106 deletions(-) diff --git a/src/device.rs b/src/device.rs index 865cd804..7c17ed2a 100644 --- a/src/device.rs +++ b/src/device.rs @@ -349,7 +349,7 @@ impl Device { load_state: false, load_rewind: false, last_rewind_saved: 0.0, - rewind_pool: std::sync::Arc::new(std::sync::Mutex::new( + rewind_pool: std::sync::Arc::new(tokio::sync::Mutex::new( std::collections::BTreeMap::new(), )), }, diff --git a/src/lib.rs b/src/lib.rs index 93056efe..1a71f457 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -105,7 +105,7 @@ fn set_app_id() { } pub fn create_runtime() -> (tokio::sync::oneshot::Sender<()>, tokio::runtime::Handle) { - let (tx, rx) = std::sync::mpsc::channel(); + let (tx, mut rx) = tokio::sync::mpsc::unbounded_channel(); let (close_tx, close_rx) = tokio::sync::oneshot::channel::<()>(); std::thread::spawn(move || { @@ -114,7 +114,7 @@ pub fn create_runtime() -> (tokio::sync::oneshot::Sender<()>, tokio::runtime::Ha rt.block_on(close_rx).unwrap(); }); - (close_tx, rx.recv().unwrap()) + (close_tx, rx.blocking_recv().unwrap()) } pub fn run(args: Args, arg_count: usize) -> std::io::Result<()> { @@ -352,9 +352,7 @@ fn android_main(app: slint::android::AndroidApp) { 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 { .. } => { - if let Ok(weak_app_window) = android::WEAK_SLINT_WINDOW.lock() - && let Some(weak_app_window) = weak_app_window.as_ref() - { + if let Some(weak_app_window) = android::WEAK_SLINT_WINDOW.blocking_lock().as_ref() { weak_app_window .upgrade_in_event_loop(move |handle| { ui::gui::save_settings(&handle); @@ -369,9 +367,9 @@ fn android_main(app: slint::android::AndroidApp) { }) .unwrap(); let app_window = ui::gui::AppWindow::new().unwrap(); - *android::WEAK_SLINT_WINDOW.lock().unwrap() = Some(app_window.as_weak()); + *android::WEAK_SLINT_WINDOW.blocking_lock() = Some(app_window.as_weak()); - *android::ANDROID_APP.lock().unwrap() = Some(app); + *android::ANDROID_APP.blocking_lock() = Some(app); let dirs = ui::get_dirs(); @@ -382,6 +380,6 @@ fn android_main(app: slint::android::AndroidApp) { ui::gui::app_window(&app_window, true); close_tx.send(()).unwrap(); - *android::WEAK_SLINT_WINDOW.lock().unwrap() = None; - *android::ANDROID_APP.lock().unwrap() = None; + *android::WEAK_SLINT_WINDOW.blocking_lock() = None; + *android::ANDROID_APP.blocking_lock() = None; } diff --git a/src/savestates.rs b/src/savestates.rs index 66643644..32f6655d 100644 --- a/src/savestates.rs +++ b/src/savestates.rs @@ -78,7 +78,7 @@ pub struct Savestate { pub last_rewind_saved: f64, #[serde(skip)] pub rewind_pool: - std::sync::Arc>>, + std::sync::Arc>>, } pub struct SavestateData { @@ -88,11 +88,11 @@ pub struct SavestateData { ra_state: Vec, } -static DEVICE_CLONE: std::sync::LazyLock>> = - std::sync::LazyLock::new(|| std::sync::Mutex::new(device::Device::new(false))); +static DEVICE_CLONE: std::sync::LazyLock>> = + std::sync::LazyLock::new(|| tokio::sync::Mutex::new(device::Device::new(false))); -static SAVES_CLONE: std::sync::LazyLock> = - std::sync::LazyLock::new(|| std::sync::Mutex::new(ui::storage::Saves::default())); +static SAVES_CLONE: std::sync::LazyLock> = + std::sync::LazyLock::new(|| tokio::sync::Mutex::new(ui::storage::Saves::default())); pub fn process_savestates(device: &mut device::Device) { let save_rewind = if device.netplay.is_none() @@ -126,18 +126,10 @@ pub fn create_savestate(device: &mut device::Device, rewind: bool, rewind_frame: let mut ra_state: Vec = vec![0; retroachievements::state_size()]; retroachievements::save_state(ra_state.as_mut_ptr(), ra_state.len()); - if let Ok(mut device_clone) = DEVICE_CLONE.lock() - && let Ok(mut saves_clone) = SAVES_CLONE.lock() - { - device_clone.clone_state(device); - saves_clone.clone_from(&device.ui.storage.saves); - } else { - ui::video::onscreen_message( - "Failed to create savestate", - ui::video::MESSAGE_LENGTH_MESSAGE_SHORT, - ); - return; - } + DEVICE_CLONE.blocking_lock().clone_state(device); + SAVES_CLONE + .blocking_lock() + .clone_from(&device.ui.storage.saves); let save_path = device.ui.storage.paths.savestate_file_path.clone(); let save_state_slot = device.ui.storage.save_state_slot; @@ -147,39 +139,32 @@ pub fn create_savestate(device: &mut device::Device, rewind: bool, rewind_frame: let mut error = false; if rewind { - if let Ok(device_clone) = DEVICE_CLONE.lock() - && let Ok(saves_clone) = SAVES_CLONE.lock() - && let Ok(mut pool) = rewind_pool.lock() - { - let mut state = device::Device::new(false); - state.clone_state(device_clone.deref()); - let key = if let Some(key) = rewind_frame { - key - } else if let Some(key) = pool.keys().last() { - key + 1 - } else { - 0 - }; - pool.insert( - key, - SavestateData { - device: state, - saves: saves_clone.clone(), - rdp_state, - ra_state, - }, - ); - if pool.len() > 30 { - pool.pop_first(); - } + let mut pool = rewind_pool.lock().await; + let mut state = device::Device::new(false); + state.clone_state(DEVICE_CLONE.lock().await.deref()); + let key = if let Some(key) = rewind_frame { + key + } else if let Some(key) = pool.keys().last() { + key + 1 } else { - error = true; + 0 + }; + pool.insert( + key, + SavestateData { + device: state, + saves: SAVES_CLONE.lock().await.clone(), + rdp_state, + ra_state, + }, + ); + if pool.len() > 30 { + pool.pop_first(); } } else { - let compressed_file = if let Ok(device_clone) = DEVICE_CLONE.lock() - && let Ok(saves_clone) = SAVES_CLONE.lock() - && let Ok(device_data) = postcard::to_stdvec(device_clone.deref()) - && let Ok(saves_data) = postcard::to_stdvec(saves_clone.deref()) + let compressed_file = if let Ok(device_data) = + postcard::to_stdvec(DEVICE_CLONE.lock().await.deref()) + && let Ok(saves_data) = postcard::to_stdvec(SAVES_CLONE.lock().await.deref()) && let Ok(compressed_file) = ui::storage::compress_file(&[ (&device_data, "device"), (&saves_data, "saves"), @@ -229,17 +214,15 @@ pub fn load_savestate(device: &mut device::Device, rewind: bool, rewind_frame: O let timeout = std::time::Duration::from_secs(1); let now = std::time::Instant::now(); loop { - if let Ok(mut pool) = device.savestate.rewind_pool.lock() - && pool.contains_key(&rewind_frame) - { + let mut pool = device.savestate.rewind_pool.blocking_lock(); + if pool.contains_key(&rewind_frame) { break pool.remove(&rewind_frame); } if now.elapsed() > timeout { break None; } } - } else if let Ok(mut pool) = device.savestate.rewind_pool.lock() - && let Some((_key, state)) = pool.pop_last() + } else if let Some((_key, state)) = device.savestate.rewind_pool.blocking_lock().pop_last() { Some(state) } else { diff --git a/src/ui/android.rs b/src/ui/android.rs index d0efa29a..cf00549d 100644 --- a/src/ui/android.rs +++ b/src/ui/android.rs @@ -13,15 +13,15 @@ const REQUEST_SELECT_ROM: jint = 1; const CONFIGURE_INPUT_PROFILE: jint = 2; const RUN_ROM: jint = 3; -pub static ANDROID_APP: std::sync::Mutex> = - std::sync::Mutex::new(None); +pub static ANDROID_APP: tokio::sync::Mutex> = + tokio::sync::Mutex::const_new(None); -pub static SELECT_ROM_TX: std::sync::Mutex< +pub static SELECT_ROM_TX: tokio::sync::Mutex< Option>>, -> = std::sync::Mutex::new(None); +> = tokio::sync::Mutex::const_new(None); -pub static WEAK_SLINT_WINDOW: std::sync::Mutex>> = - std::sync::Mutex::new(None); +pub static WEAK_SLINT_WINDOW: tokio::sync::Mutex>> = + tokio::sync::Mutex::const_new(None); bind_java_type! { DocumentsContract => "android.provider.DocumentsContract", @@ -197,9 +197,7 @@ fn start_configure_input_profile_on_jvm( dinput: bool, deadzone: i32, ) -> jni::errors::Result<()> { - if let Ok(app) = ANDROID_APP.lock() - && let Some(app) = app.as_ref() - { + if let Some(app) = ANDROID_APP.blocking_lock().as_ref() { let raw_activity_global = app.activity_as_ptr() as jni::sys::jobject; let activity = unsafe { env.as_cast_raw::>(&raw_activity_global)? }; @@ -256,9 +254,7 @@ fn start_run_rom_on_jvm( netplay: Option, weak: slint::Weak, ) -> jni::errors::Result<()> { - if let Ok(app) = ANDROID_APP.lock() - && let Some(app) = app.as_ref() - { + if let Some(app) = ANDROID_APP.blocking_lock().as_ref() { let raw_activity_global = app.activity_as_ptr() as jni::sys::jobject; let activity = unsafe { env.as_cast_raw::>(&raw_activity_global)? }; @@ -330,9 +326,7 @@ fn start_run_rom_on_jvm( } fn get_vm() -> Option { - if let Ok(app) = ANDROID_APP.lock() - && let Some(app) = app.as_ref() - { + if let Some(app) = ANDROID_APP.blocking_lock().as_ref() { Some(unsafe { JavaVM::from_raw(app.vm_as_ptr().cast()) }) } else { None @@ -431,9 +425,7 @@ pub fn open_uri(path: &str) { } fn open_uri_on_jvm(env: &mut Env<'_>, path: &str) -> jni::errors::Result<()> { - if let Ok(app) = ANDROID_APP.lock() - && let Some(app) = app.as_ref() - { + if let Some(app) = ANDROID_APP.blocking_lock().as_ref() { let raw_activity_global = app.activity_as_ptr() as jni::sys::jobject; let activity = unsafe { env.as_cast_raw::>(&raw_activity_global)? }; @@ -459,12 +451,8 @@ pub async fn select_rom(rom_dir: slint::SharedString) -> Option>(); - if let Ok(mut tx_lock) = SELECT_ROM_TX.lock() { - tx_lock.replace(tx); - } else { - eprintln!("Error locking SELECT_ROM_TX"); - return None; - } + SELECT_ROM_TX.lock().await.replace(tx); + rx.await.unwrap_or(None) } else { eprintln!("Android app not initialized"); @@ -481,9 +469,7 @@ pub async fn select_gb_ram(_player: i32) -> Option { } fn select_rom_on_jvm(env: &mut Env<'_>, rom_dir: String) -> jni::errors::Result<()> { - if let Ok(app) = ANDROID_APP.lock() - && let Some(app) = app.as_ref() - { + if let Some(app) = ANDROID_APP.blocking_lock().as_ref() { let raw_activity_global = app.activity_as_ptr() as jni::sys::jobject; let activity = unsafe { env.as_cast_raw::>(&raw_activity_global)? }; @@ -507,9 +493,7 @@ fn select_rom_on_jvm(env: &mut Env<'_>, rom_dir: String) -> jni::errors::Result< } pub fn get_dirs() -> ui::Dirs { - if let Ok(app) = ANDROID_APP.lock() - && let Some(app) = app.as_ref() - { + if let Some(app) = ANDROID_APP.blocking_lock().as_ref() { ui::Dirs { config_dir: app.internal_data_path().unwrap().join("config"), data_dir: app.external_data_path().unwrap().join("data"), @@ -559,9 +543,7 @@ fn get_file_from_uri_on_jvm( env: &mut Env<'_>, path: String, ) -> jni::errors::Result> { - if let Ok(app) = ANDROID_APP.lock() - && let Some(app) = app.as_ref() - { + if let Some(app) = ANDROID_APP.blocking_lock().as_ref() { let raw_activity_global = app.activity_as_ptr() as jni::sys::jobject; let activity = unsafe { env.as_cast_raw::>(&raw_activity_global)? }; let path = JString::from_str(env, path)?; @@ -600,8 +582,7 @@ pub extern "system" fn Java_io_github_gopher64_gopher64_SlintActivity_nativeOnAc if result_code == AndroidActivity::RESULT_OK(env)? { match request_code { REQUEST_SELECT_ROM => { - if let Ok(mut tx_lock) = SELECT_ROM_TX.lock() - && let Some(tx) = tx_lock.take() + if let Some(tx) = SELECT_ROM_TX.blocking_lock().take() && !intent_data.is_null() { let result_intent = @@ -612,9 +593,7 @@ pub extern "system" fn Java_io_github_gopher64_gopher64_SlintActivity_nativeOnAc return Ok(()); } - if let Ok(app) = ANDROID_APP.lock() - && let Some(app) = app.as_ref() - { + if let Some(app) = ANDROID_APP.blocking_lock().as_ref() { let raw_activity_global = app.activity_as_ptr() as jni::sys::jobject; let activity = unsafe { env.as_cast_raw::>(&raw_activity_global)? @@ -635,9 +614,7 @@ pub extern "system" fn Java_io_github_gopher64_gopher64_SlintActivity_nativeOnAc } } CONFIGURE_INPUT_PROFILE => { - if let Ok(weak_app_window) = WEAK_SLINT_WINDOW.lock() - && let Some(weak_app_window) = weak_app_window.as_ref() - { + if let Some(weak_app_window) = WEAK_SLINT_WINDOW.blocking_lock().as_ref() { let config = ui::config::Config::new(); ui::gui::update_input_profiles(&weak_app_window, &config); } @@ -659,9 +636,7 @@ pub extern "system" fn Java_io_github_gopher64_gopher64_SlintActivity_nativeOnAc { let _ = std::fs::remove_file(cheats_path); } - if let Ok(weak_app_window) = WEAK_SLINT_WINDOW.lock() - && let Some(weak_app_window) = weak_app_window.as_ref() - { + if let Some(weak_app_window) = WEAK_SLINT_WINDOW.blocking_lock().as_ref() { weak_app_window .upgrade_in_event_loop(move |handle| { ui::gui::update_recent_roms(&handle, file_path.into());