Fix backend deadlock when mpv output exceeds the stdout pipe buffer - #446
Open
jfrmorales wants to merge 1 commit into
Open
jfrmorales wants to merge 1 commit into
jfrmorales wants to merge 1 commit into
Conversation
mpv is spawned with stdout piped, but the pipe was only read after cmd.wait() returned. On Linux a pipe has a limited buffer (~64KB), so when mpv (or its yt-dlp hook) writes more than that, mpv blocks forever on write(), never exits, cmd.wait() never returns, and the whole backend deadlocks with the UI frozen. Drain stdout in a concurrent task while mpv runs, then use the collected output as the error message on a non-success exit. This keeps the exact error-reporting behavior (the message is still surfaced to the user) and removes the deadlock. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes a hard backend deadlock that freezes the whole app when a stream fails or drops. The fix drains mpv's stdout concurrently instead of only after the process exits, while keeping the exact error message that is currently shown to the user.
Symptom
When playing a channel or losing signal, the UI froze completely and one CPU core pegged at 100%. The window could not be closed and channels could not be switched — the process had to be killed manually (
killall -9 open_tv).Environment where it reproduces
dev.fredol.open-tv)yt-dlphookThe pipe-buffer condition below is OS-level and not NVIDIA-specific, but this setup made it trigger reliably (verbose hook/log output on flaky IPTV links).
Root cause
In
src-tauri/src/mpv.rs, mpv is spawned withstdout(Stdio::piped()), but the pipe was only read aftercmd.wait()returned:A Linux pipe has a limited buffer (~64KB). If mpv (or its
yt-dlpsubprocess) writes more than that to stdout, mpv blocks indefinitely onwrite()waiting for the buffer to drain. Nothing reads the buffer until mpv exits — but mpv can't exit while it's blocked writing. Socmd.wait()never returns, the async task and the state locks behind it are held forever, and the UI deadlocks.Fix
Spawn a small task that drains stdout line-by-line while mpv runs, then use the collected output as the error message on a non-success exit:
Because the pipe is read continuously, the buffer can never fill, so mpv can never block on write and
cmd.wait()always returns.The error-reporting behavior is preserved: on a non-zero exit the collected output is surfaced to the user exactly as before (with the same
"Mpv encountered an unknown error"fallback when there is no output). The cancellation path is unchanged; the drain task ends on its own via EOF when mpv is killed.Testing
cargo checkpasses.