On 13 July 2015 at 16:42, Ian Lance Taylor <
ia...@golang.org> wrote:
> You can poll the wait status in a loop with a sleep by calling
> syscall.Wait4 passing syscall.WNOHANG. You can use a lock to ensure
> that you never call Wait4 and Kill simultaneously. Then don't Kill
> after the Wait4 succeeds. This is ugly because it requires a polling
> loop.
Thanks for the tip about directly calling Wait4! Together with waiting
for syscall.SIGCHLD the code avoided the busy wait and eliminated an
extra goroutine. I used a select to wait both for the child signal and
a notification to terminate the child:
p, err := os.StartProcess(path, argv, &attr)
...
signalChild := make(chan os.Signal, 1)
defer close(signalChild)
signal.Notify(signalChild, syscall.SIGCHLD)
defer signal.Stop(signalChild)
var ws syscall.WaitStatus
childWait: for {
select {
case _ = (<-terminateNotification):
err := p.Signal(syscall.SIGTERM)
...
case _ = (<-signalChild):
pid, err := syscall.Wait4(p.Pid, &ws, syscall.WNOHANG, nil)
...
if pid != 0 {
break childWait
}
}
}
p.Release()
if ws.Exited() && ws.ExitStatus() == 0 {
...
}
>
> Or, this is probably impossible in Go today, but if you are running on
> GNU/Linux you could use CLONE_NEWPID to start the process. Then open
> one of the files in /proc/PID/ns. That will keep the PID namespace
> alive until the descriptor is closed. That means that the PID will
> not be reused.
CLONE_NEWPID requires CAP_SYS_ADMIN on Linux, so it does not work for
non-privileged processes even if
https://golang.org/pkg/syscall/#StartProcess and syscall.CLONE_NEWPID
indicate that it should be possible to code that in Go. Still I keep
that in mind for more complex cases.