mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-07-24 12:44:18 +08:00
a3598fd976
The updater's relaunch() (and app.restart()) triggers ExitRequested with code RESTART_EXIT_CODE, which the handler treated as a regular exit: it called api.prevent_exit() and spawned an async cleanup task. However Tauri silently ignores prevent_exit() for restart requests (see ExitRequestApi::prevent_exit docs), so the event loop keeps shutting down regardless and fires every plugin's RunEvent::Exit hook. Two threads then deadlock: - the spawned cleanup task runs save_window_state on a tokio worker, holding the window-state plugin's internal mutex while querying window geometry, which dispatches to the main thread and blocks; - the main thread, already inside the plugin's own RunEvent::Exit hook, blocks on that same mutex. The app freezes forever on the restarting screen with the update already installed; force-quit + reopen comes back on the new version (#3998). Confirmed on macOS by sampling the frozen process: main thread parked in tauri_plugin_window_state save_window_state mutex lock, tokio worker parked in is_maximized -> mpsc recv. Fix: classify exit requests (None / restart / user exit) and let restart requests fall through untouched to Tauri's default restart flow (RunEvent::Exit -> re-exec). On that path window state is saved by the plugin's exit hook on the main thread, the tray icon is cleaned up by Tauri's internal cleanup_before_exit, and proxy/live config restore is unnecessary because the new instance takes over immediately. The regular exit path (tray quit) is unchanged. With the fix, a simulated updater relaunch (request_restart) re-execs the new process in under 200ms, 3/3 runs; normal quit still performs full cleanup. Co-authored-by: thisTom <19346741+thisTom@users.noreply.github.com>