Skip to content

fix(updater): resolve macOS update deadlock (#4206)#4387

Open
juliantanx wants to merge 1 commit into
farion1231:mainfrom
juliantanx:fix/update-deadlock-4206
Open

fix(updater): resolve macOS update deadlock (#4206)#4387
juliantanx wants to merge 1 commit into
farion1231:mainfrom
juliantanx:fix/update-deadlock-4206

Conversation

@juliantanx

Copy link
Copy Markdown

Summary

Fixes the app freeze / permanent hang when clicking "Update" on macOS (Apple Silicon), as reported in #4206.

Root cause: install_update_and_restart runs on a tokio worker thread. Before restarting, it called save_window_state_before_exit, which acquires the window-state plugin lock and queries the main thread for window geometry. When restart_process then triggers ExitRequested(RESTART_EXIT_CODE), the main thread enters the exit event loop and its window-state Exit hook tries to acquire the same lock — mutual deadlock (_pthread_mutex_firstfit_lock_slow / __psynch_mutexwait).

Fix: Remove the manual save_window_state_before_exit / cleanup_before_exit calls from the macOS/Linux update path, aligning it with the DeferToTauriRestart handler in lib.rs (which was already corrected for the identical deadlock in #3998):

  • Window state is saved by the plugin's own Exit hook on the main thread (no cross-thread lock contention)
  • Proxy/Live config is restored automatically by the new instance on startup

Additional defensive improvements (not the core fix, but prevent related hangs):

Related Issue

Closes #4206

Changed Files

File Change
src-tauri/src/commands/settings.rs Remove deadlock-causing cleanup calls on macOS/Linux; add timeouts and progress events
src/components/settings/AboutSection.tsx Listen to download progress events; display percentage on update button

Test Plan

  • pnpm typecheck passes
  • pnpm format:check passes
  • pnpm test:unit passes (338/338)
  • cargo clippy passes (Rust toolchain not available in current env — needs CI verification)
  • Manual test: click "Update" on macOS Apple Silicon — app should download, install, and restart without freezing
  • Manual test: disconnect network, click "Update" — should show timeout error after 35s instead of hanging

…progress

Remove save_window_state_before_exit and cleanup_before_exit from the
macOS/Linux path in install_update_and_restart. These calls run on a
tokio worker thread and acquire the window-state plugin lock while
querying the main thread for window geometry. When restart_process
subsequently triggers ExitRequested(RESTART_EXIT_CODE), the main
thread's Exit hook tries to acquire the same lock — causing a permanent
mutex deadlock (the app freezes with a spinning cursor and never
restarts). This aligns the update path with the DeferToTauriRestart
handler in lib.rs, which was already fixed for the same deadlock
pattern in farion1231#3998.

Additionally:
- Wrap updater.check() with tokio::time::timeout(35s) and
  update.download() with tokio::time::timeout(300s) as defensive
  guards against network hangs.
- Emit "update-download-progress" events during download so the
  frontend can display real-time download percentage.
- Do not use UpdaterBuilder::timeout() to avoid the timeout-leaking-
  to-download bug documented in tauri-apps/plugins-workspace#2372.

Closes farion1231#4206

Copy link
Copy Markdown
Owner

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: bbc2b1150e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +267 to +269
// 正确做法与 lib.rs 中 DeferToTauriRestart 路径一致:
// - 窗口状态:Tauri 的 Exit 钩子在主线程保存(同线程读取几何,无死锁)
// - 代理/Live 配置:重启后新实例立即接管并恢复代理状态,无需手动清理

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Restore exit compensation before direct restart

This path now relies on Tauri Exit hooks/new startup to save state and repair proxy/Live config, but the call immediately after this block is restart_process, whose helper in src-tauri/src/lib.rs documents that it uses tauri::process::restart and bypasses the event loop and plugin RunEvent::Exit hooks. On macOS/Linux updates, users who have proxy takeover active now exit with Live configs still pointing at the old local proxy until the new instance successfully reaches crash recovery (and they stay broken if restart/startup fails), and window geometry is no longer saved on update restarts; either use the Tauri restart path that actually runs those hooks or keep the explicit safe compensation before the direct restart.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

CC Switch 3.16.3 hangs during update on macOS 26.5.1

2 participants