-
Notifications
You must be signed in to change notification settings - Fork 18.8k
Description
What version of Go are you using (go version)?
$ go version go version go1.20.4 linux/amd64
Does this issue reproduce with the latest release?
Yes.
What operating system and processor architecture are you using (go env)?
go env Output
$ go env GO111MODULE="" GOARCH="amd64" GOBIN="" GOCACHE="/home/mitar/.cache/go-build" GOENV="/home/mitar/.config/go/env" GOEXE="" GOEXPERIMENT="" GOFLAGS="" GOHOSTARCH="amd64" GOHOSTOS="linux" GOINSECURE="" GOMODCACHE="/home/mitar/.go/pkg/mod" GONOPROXY="" GONOSUMDB="" GOOS="linux" GOPATH="/home/mitar/.go" GOPRIVATE="" GOPROXY="https://proxy.golang.org,direct" GOROOT="/usr/local/go" GOSUMDB="sum.golang.org" GOTMPDIR="" GOTOOLDIR="/usr/local/go/pkg/tool/linux_amd64" GOVCS="" GOVERSION="go1.20.4" GCCGO="/usr/bin/gccgo" GOAMD64="v1" AR="ar" CC="gcc" CXX="g++" CGO_ENABLED="1" GOMOD="/tmp/git/go.mod" GOWORK="" CGO_CFLAGS="-O2 -g" CGO_CPPFLAGS="" CGO_CXXFLAGS="-O2 -g" CGO_FFLAGS="-O2 -g" CGO_LDFLAGS="-O2 -g" PKG_CONFIG="pkg-config" GOGCCFLAGS="-fPIC -m64 -pthread -Wl,--no-gc-sections -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build4256193346=/tmp/go-build -gno-record-gcc-switches"
What did you do?
I tried to run the following program:
package main
import (
"io"
"log"
"os"
"os/exec"
"sync"
"syscall"
"time"
)
func execute() error {
cmd := exec.Command("bash", "-c", "(sleep infinity)")
stdout, _ := cmd.StdoutPipe()
stderr, _ := cmd.StderrPipe()
if err := cmd.Start(); err != nil {
log.Printf("Error executing command: %s......\n", err.Error())
return err
}
go func() {
<-time.After(10 * time.Second)
log.Printf("sending SIGTERM")
cmd.Process.Signal(syscall.SIGTERM)
}()
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
io.Copy(os.Stdout, stdout)
}()
wg.Add(1)
go func() {
defer wg.Done()
io.Copy(os.Stderr, stderr)
}()
wg.Wait()
if err := cmd.Wait(); err != nil {
log.Printf("Error waiting for command execution: %s......\n", err.Error())
return err
}
log.Printf("end")
return nil
}
func main() {
execute()
}This is a variation of an example from #38268. I constructed this example but in my real app I do not just copy subprocess stdout to main stdout, but I do a transformation on it. Anyway, the issue is that it seems when bash subprocess gets terminated, reader does not get EOF and so io.Copy does not end, so wg.Wait never finishes, so we never get to cmd.Wait. If I comment out wg.Wait, then cmd.Wait correctly reaps the subprocess (but of course it could mean not everything gets copied).
Currently, documentation of StdoutPipe and StderrPipe requires:
It is thus incorrect to call Wait before all reads from the pipe have completed.
But it seems it is not possible to always know when all reads from the pipe have completed?
What did you expect to see?
2023/05/19 19:44:58 sending SIGTERM
2023/05/19 19:44:58 Error waiting for command execution: signal: terminated......
And programs terminates.
What did you see instead?
2023/05/19 19:44:58 sending SIGTERM
And program never terminates.