-
Notifications
You must be signed in to change notification settings - Fork 18.8k
Closed as duplicate of#10338
Closed as duplicate of#10338
Copy link
Description
Go version
N/A
Output of go env in your module/workspace:
N/AWhat did you do?
When using Cmd.Run to run a program, we need to make it serve, feed its input from another Goroutine, and we don't know the input ahead or when input will be closed.
A real case is git cat-file --batch-check.
- We need to start the process in background, and callers can send the object ID to its stdin, and read output to parse
- The
gitruns as a background service, the caller doesn't close the input ahead, and the caller don't know how many object IDs it needs to check ahead. - But
git cat-file --batch-checkcan exit immediacy if it runs in a non-git directory
func TestCmdPipe(t *testing.T) {
inR, inW := io.Pipe()
outR, outW := io.Pipe()
errBuf := &bytes.Buffer{}
_ = inW
cmd := exec.Cmd{
Path: "/bin/bash", // the real case is `git cat-file --batch-check`
Args: []string{"/bin/bash", "no-such-script"},
Stdin: inR,
Stdout: outW,
Stderr: errBuf,
// WaitDelay: time.Second, // does not help
}
err := cmd.Start()
assert.NoError(t, err)
// I know that inW.Close will make Wait exit, but we can't do that
// because the inW is used in another goroutine and keeps querying the object IDs if the process runs
err = cmd.Wait() // fatal error: all goroutines are asleep - deadlock!
assert.NoError(t, err)
_ = outR
}What did you see happen?
Deadlock
- The
inWgoroutine doesn't know the process exits (Wait never returns), so it is unable to close the inW pipe - The
Waitkeeps waiting becauseinWcan't be closed, then deadlock
What did you expect to see?
Is it possible to know that the process has exited before Wait causes the deadlock?
If I can know that the process has exited in another Goroutine, I can manually close the inW, then everything goes well.
Metadata
Metadata
Assignees
Labels
No labels