Good day!
I faced a corner case of cmd.Exec usage and want to find out if it's designed behavior.
go version go1.6.2 darwin/amd64 and linux
Let's assume we use cmd.Exec to start some process, that can fork and dies, but the fork will live forever. For example:
#!/usr/bin/env python
import os
import time
pid = os.fork()
if pid == 0:
while True:
time.sleep(10)
print "main process has quited"
The real script is much more complicated but it's not important.
Also there is a go code:
package main
import (
"io"
"log"
"os/exec"
)
func main() {
cmd := exec.Command("./forker.py")
rd, wr := io.Pipe()
cmd.Stdout = wr
go func() {
b := make([]byte, 100)
for {
nn, err := rd.Read(b)
if nn > 0 {
log.Printf("%s", b[:nn])
}
if err != nil {
log.Fatal(err)
return
}
}
}()
if err := cmd.Start(); err != nil {
log.Fatal(err)
}
log.Printf("PID %d", cmd.Process.Pid)
if err := cmd.Wait(); err != nil {
log.Fatal(err)
}
}
The output would be like this:
2016/07/13 23:40:20 PID 90614
2016/07/13 23:40:20 main process has quited
but the Go process will hang forever, because of waiting on:
https://github.com/golang/go/blob/release-branch.go1.6/src/os/exec/exec.go#L401I think, because stdout fd of child process would not be closed .
On the other hand the next code works perfectly and does not hang:
package main
import (
"log"
"os/exec"
)
func main() {
cmd := exec.Command("./forker.py")
rd, err := cmd.StdoutPipe()
if err != nil {
log.Fatal(err)
}
go func() {
b := make([]byte, 100)
for {
nn, err := rd.Read(b)
if nn > 0 {
log.Printf("%s", b[:nn])
}
if err != nil {
log.Fatal(err)
return
}
}
}()
if err := cmd.Start(); err != nil {
log.Fatal(err)
}
log.Printf("PID %d", cmd.Process.Pid)
if err := cmd.Wait(); err != nil {
log.Fatal(err)
}
}
So I would like to find out if setting cmd.Stdout explicitly is not expected.
Thanks!