fix: replace blocking waitUntilExit() with async continuation

proc.waitUntilExit() blocks cooperative thread pool threads and
deadlocks in Swift Concurrency Task context because NSRunLoop
notifications aren't processed. Replace with terminationHandler +
withCheckedContinuation pattern.
This commit is contained in:
yumoqing 2026-06-30 22:24:48 +08:00
parent 68806e1190
commit acb232d38b

View File

@ -106,8 +106,8 @@ public final class FFmpegRecorder: StreamRecorderEngine {
throw RecordingError.unknown("无法启动 ffmpeg: \(error.localizedDescription)")
}
//
proc.waitUntilExit()
// cooperative thread
await waitForProcess(proc)
stderrPipe.fileHandleForReading.readabilityHandler = nil
isRecording = false
@ -136,6 +136,22 @@ public final class FFmpegRecorder: StreamRecorderEngine {
// MARK: - Private
/// Async-friendly process wait uses terminationHandler + continuation
/// instead of blocking waitUntilExit() which deadlocks in Task context
private func waitForProcess(_ proc: Process) async {
guard proc.isRunning else { return }
await withCheckedContinuation { (continuation: CheckedContinuation<Void, Never>) in
proc.terminationHandler = { _ in
continuation.resume()
}
// Race condition: process may have exited between isRunning check and setting handler
if !proc.isRunning {
proc.terminationHandler = nil
continuation.resume()
}
}
}
private func findFFmpeg() -> String {
let paths = [
"/opt/homebrew/bin/ffmpeg",
@ -186,7 +202,7 @@ public final class FFmpegRecorder: StreamRecorderEngine {
do {
try proc.run()
proc.waitUntilExit()
await waitForProcess(proc)
} catch {
throw RecordingError.unknown("无法分析输出文件")
}
@ -269,7 +285,7 @@ public final class FFmpegRecorder: StreamRecorderEngine {
do {
try proc.run()
proc.waitUntilExit()
await waitForProcess(proc)
} catch {
return nil
}