Reputation: 45214
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
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:
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; andos/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