If I have the PID of a process, is os.FindProcess enough to test for the existing of the process? I mean if it returns err
can I assume that it's terminated (or killed)?
Edit:
I've just wrote a wrapper function around kill -s 0
(old-style bash process testing). This works without any problem, but I'm still happy if there is other solutions (done with go libraries) to this problem.:
func checkPid(pid int) bool {
out, err := exec.Command("kill", "-s", "0", strconv.Itoa(pid)).CombinedOutput()
if err != nil {
log.Println(err)
}
if string(out) == "" {
return true // pid exist
}
return false
}
Here is the traditional unix way to see if a process is alive - send it a signal of 0 (like you did with your bash example).
From kill(2)
:
If sig is 0, then no signal is sent, but error checking is still per‐ formed; this can be used to check for the existence of a process ID or process group ID.
And translated into Go
package main
import (
"fmt"
"log"
"os"
"strconv"
"syscall"
)
func main() {
for _, p := range os.Args[1:] {
pid, err := strconv.ParseInt(p, 10, 64)
if err != nil {
log.Fatal(err)
}
process, err := os.FindProcess(int(pid))
if err != nil {
fmt.Printf("Failed to find process: %s
", err)
} else {
err := process.Signal(syscall.Signal(0))
fmt.Printf("process.Signal on pid %d returned: %v
", pid, err)
}
}
}
When you run it you get this, showing that process 123 is dead, process 1 is alive but not owned by you and process 12606 is alive and owned by you.
$ ./kill 1 $$ 123
process.Signal on pid 1 returned: operation not permitted
process.Signal on pid 12606 returned: <nil>
process.Signal on pid 123 returned: no such process
On unix like systems (linux, freebsd, etc) os.FindProcess will never return an error. I don't know what happens on Windows. This means you won't know if the PID is correct until you try to use the *os.Process for something.
You can look at the code here.
If a previously known pid is not found in the system (not sure of go functions), it means process has definitely terminated and has been joined (on Unix, with wait call) too.
But other way around is not necessarily true. Just because a pid exists, it does not quarantee it is same process as before. There are only 65535 valid pids in standard Linux for example, and they can get re-used when there is a wrap-around. However, if you check reasonably often, for practical purposes you don't need to care about this (as long as pid of wrong new process being found is not a security vulnerability or something else critical, which somebody might try to trigger intentionally for malicious purposes).
Related links (and Related questions on their right columns):
You can also just use syscall.Kill
. It amounts to less code.
killErr := syscall.Kill(pid, syscall.Signal(0))
procExists := killErr == nil
On Windows checking the result of os.FindProcess()
seems to be enough to check if process is running.
func isProcessRunning(pid int) bool {
_, err = os.FindProcess(pid)
if err != nil {
return false
}
if runtime.GOOS == "windows" {
return true
}
return false // further checking for other systems then Windows is not supported here
}