1

My golang program starts a service program which is supposed to run forever, like this:

cmd := exec.Command("/path/to/service")
cmd.Start()

I do NOT want to wait for the termination of "service" because it is supposed to be running forever. However, if service starts with some error (e.g. it will terminate if another instance is already running), the child process will exit and become zombie.

My question is, after cmd.Start(), can I somehow detect if the child process is still running, rather than becomes a zombie? The preferred way might be:

if cmd.Process.IsZombie() {
    ... ...
}

or,

procStat := cmd.GetProcessStatus()
if procStat.Zombie == true {
    ... ...
}

i.e. I hope there are some way to get the status of a (child) process without waiting for its exit code, or, to "peek" its status code without blocking.

Thanks!

Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189
xrfang
  • 1,754
  • 4
  • 18
  • 36
  • This is how unix process work, you always need to `wait` on them. The `init` process (PID 1) does this for you if they are left when the parent exits, but you should clean up your own processes. – JimB Sep 22 '17 at 18:03
  • An alternative, from answer here: https://stackoverflow.com/questions/36050503/golang-child-processes-become-zombies it seems that if the parent process ignores SIGCHLD, then a child process will not become zombie if it exit? If this is correct, then I might just use FindProcess to see if the sub process is still there? – xrfang Sep 23 '17 at 04:38

2 Answers2

4

Judging from the docs the only way to get the process state is to call os.Process.Wait. So it seems you will have to call wait in a goroutine, and then you can easily check if that goroutine has exited yet:

var cmd exec.Cmd

done := make(chan error, 1)
go func() {
    done <- cmd.Wait()
}()

select {
case err := <-done:
    // inspect err to check if service exited normally
default:
    // not done yet
}
Peter
  • 29,454
  • 5
  • 48
  • 60
  • This is exactly what I do *not* want. Because I cannot control the goroutine, and if it does not exit, I will have to use a for loop or something ? This makes the program structure clumsy... – xrfang Sep 23 '17 at 04:36
  • 1
    Not sure what mean by "I cannot control the goroutine". If the process does not exit, it simply blocks on Wait() forever. The check for whether it has exited or not is the select statement in the main goroutine. – Peter Sep 25 '17 at 09:40
1

The best solution (for me) is:

  1. add a signal handler listen for SIGCHLD
  2. on receiving SIGCHLD, call cmd.Wait()

This way, the zombie process will disappear.

xrfang
  • 1,754
  • 4
  • 18
  • 36