ahmet alp balkan
ahmet alp balkan

Reputation: 45214

How to check if a process started in the background still running?

It looks like if you create a subprocess via exec.Cmd and Start() it, the Cmd.Process field is populated right away, however Cmd.ProcessState field remains nil until the process exits.

   // ProcessState contains information about an exited process,
   // available after a call to Wait or Run.
   ProcessState *os.ProcessState

So it looks like I can't actually check the status of a process I Start()ed while it's still running?

It makes no sense to me ProcessState is set when the process exits. There's an ProcessState.Exited() method which will always return true in this case.


So I tried to go this route instead: cmd.Process.Pid field exists right after I cmd.Start(), however it looks like os.Process doesn't expose any mechanisms to check if the process is running.

os.FindProcess says:

On Unix systems, FindProcess always succeeds and returns a Process for the given pid, regardless of whether the process exists.

which isn't useful –and it seems like there's no way to go from os.Process to an os.ProcessState unless you .Wait() which defeats the whole purpose (I want to know if the process is running or not before it has exited).

Upvotes: 3

Views: 1821

Answers (1)

torek
torek

Reputation: 488203

I think you have two reasonable options here:

  • Spin off a goroutine that waits for the process to exit. When the wait is done, you know the process exited. (Positive: pretty easy to code correctly; negative: you dedicate an OS thread to waiting.)

  • Use syscall.Wait4() on the published Pid. A Wait4 with syscall.WNOHANG set returns immediately, filling in the status.

It might be nice if there were an exported os or cmd function that did the Wait4 for you and filled in the ProcessState. You could supply WNOHANG or not, as you see fit. But there isn't.


The point of ProcessState.Exited() is to distinguish between all the various possibilities, including:

  • process exited normally (with a status byte)
  • process died due to receiving an unhandled signal

See the stringer for ProcessState. Note that there are more possibilities than these two ... only there seems to be no way to get the others into a ProcessState. The only calls to syscall.Wait seem to be:

  • syscall/exec_unix.go: after a failed exec, to collect zombies before returning an error; and
  • os/exec_unix.go: after a call to p.blockUntilWaitable().

If it were not for the blockUntilWaitable, the exec_unix.go implementation variant for wait() could call syscall.Wait4 with syscall.WNOHANG, but blockUntilWaitable itself ensures that this is pointless (and the goal of this particular wait is to wait for exit anyway).

Upvotes: 4

Related Questions