From 71aef2e83cda14968ac72bd3850f7b3f23d1e624 Mon Sep 17 00:00:00 2001 From: Tunglies <77394545+Tunglies@users.noreply.github.com> Date: Tue, 27 Oct 2026 19:53:06 +0800 Subject: [PATCH] refactor(sysopt): drop redundant lock and busy-wait The proxy target pair sat behind an Arc with no readers and an Arc that was never cloned; both writers already serialize on update_lock, so store the pair inside that mutex and delete the RwLock. refresh_guard waited for the guard to become ready with a yield_now spin at full CPU while holding guard_operation_lock; a 10 ms sleep keeps the same wait condition and lock scope without the spin. --- src-tauri/src/core/sysopt.rs | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/src-tauri/src/core/sysopt.rs b/src-tauri/src/core/sysopt.rs index 9b3d158dc..6fccb0e3e 100644 --- a/src-tauri/src/core/sysopt.rs +++ b/src-tauri/src/core/sysopt.rs @@ -241,20 +241,19 @@ async fn current_os_proxy_state(sys: Sysproxy, auto: Autoproxy) -> OsProxyState } pub(crate) struct Sysopt { - update_lock: TokioMutex<()>, + // Owns the proxy target pair; every reader and writer goes through this lock. + update_lock: TokioMutex<(Sysproxy, Autoproxy)>, guard_operation_lock: TokioMutex<()>, reset_sysproxy: AtomicBool, - inner_proxy: Arc>, guard: Arc>, } impl Default for Sysopt { fn default() -> Self { Self { - update_lock: TokioMutex::new(()), + update_lock: TokioMutex::new((Sysproxy::default(), Autoproxy::default())), guard_operation_lock: TokioMutex::new(()), reset_sysproxy: AtomicBool::new(false), - inner_proxy: Arc::new(RwLock::new((Sysproxy::default(), Autoproxy::default()))), guard: Arc::new(RwLock::new(GuardMonitor::new(GuardType::None, Duration::from_secs(30)))), } } @@ -361,7 +360,7 @@ impl Sysopt { } } while self.access_guard().read().get_state().is_pendding() { - tokio::task::yield_now().await; + tokio::time::sleep(Duration::from_millis(10)).await; } // `start()` false may also mean a guard was already running. !self.access_guard().read().get_state().is_stopped() @@ -413,14 +412,17 @@ impl Sysopt { } /// init the sysproxy + #[allow( + clippy::significant_drop_tightening, + reason = "the update lock must stay held until the OS write finishes; wait_idle relies on it" + )] pub(super) async fn update_sysproxy(&self) -> Result<()> { - let _lock = self.update_lock.lock().await; + let mut inner_proxy = self.update_lock.lock().await; let verge = Config::verge().await.latest_arc(); // Configured, not live: this runs while the Core is being started or restarted, and // asking a Core that is not up yet would only fall back here anyway. let port = MixedPort::desired().await; let pac_port = server::embedded_server_port()?; - // 先 await, 避免持有锁导致的 Send 问题 let bypass = get_bypass().await; let (sys_enable, pac_enable, proxy_host, proxy_guard) = ( @@ -431,7 +433,7 @@ impl Sysopt { ); let (sys, auto, guard_type) = { - let (sys, auto) = &mut *self.inner_proxy.write(); + let (sys, auto) = &mut *inner_proxy; sys.host = proxy_host.into(); sys.port = port; sys.bypass = bypass.into(); @@ -528,6 +530,10 @@ impl Sysopt { } /// reset the sysproxy + #[allow( + clippy::significant_drop_tightening, + reason = "the update lock must stay held until the disable finishes; wait_idle relies on it" + )] pub(super) async fn reset_sysproxy(&self) -> Result<()> { if self .reset_sysproxy @@ -539,13 +545,13 @@ impl Sysopt { defer! { self.reset_sysproxy.store(false, Ordering::SeqCst); } - let _lock = self.update_lock.lock().await; + let mut inner_proxy = self.update_lock.lock().await; let _guard_operation = self.guard_operation_lock.lock().await; let drained = self.stop_proxy_guard_locked().await; // 直接关闭所有代理 let (sys, auto) = { - let (sys, auto) = &mut *self.inner_proxy.write(); + let (sys, auto) = &mut *inner_proxy; sys.enable = false; auto.enable = false; (sys.clone(), auto.clone())