Reputation: 17117
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
}
Upvotes: 23
Views: 39543
Reputation: 19985
Here is one way of how to check if a process exists/running with Golang on Windows.
We execute the command:
TASKLIST /V /NH /FI "PID eq 23232"
Which can return either:
INFO: No tasks are running which match the specified criteria.
Or if found:
Image Name PID Session Name Session# Mem Usage Status User Name CPU Time Window Title
========================= ======== ================ =========== ============ =============== ================================================== ============ ========================================================================
chrome.exe 23232 Console 1 42,472 K Unknown THANOS\MARVEL 0:00:00 N/A
Here is a function that takes advantage of this information.
func isProcessRunning(pid int) bool {
cmd := exec.Command("TASKLIST", "/FI", fmt.Sprintf("PID eq %d", pid))
result, err := cmd.Output()
if err != nil {
return false
}
return !bytes.Contains(result, []byte("No tasks are running"))
}
The best thing about this is you can find the process by other parameters too:
ImageName eq, ne Image Name String
PID eq, ne, gt, lt, ge, le Process ID, A Positive integer.
Session eq, ne, gt, lt, ge, le Any valid session number.
SessionName eq, ne String
Status eq, ne RUNNING | NOT RESPONDING | UNKNOWN
CPUTime eq, ne, gt, lt, ge, le Time hh:mm:ss
MemUsage eq, ne, gt, lt, ge, le Memory usage in KB, specify a valid integer.
Username eq, ne User name ([Domain\]User).
Services eq, ne Service Name String
Windowtitle eq, ne Window Title String
Modules eq, ne DLL Name String
Upvotes: 2
Reputation: 19
After searching for a few hours, the correct answer to know if a process is running on Windows is the following:
func CheckProcessLife(pid int){
cmd,_ := exec.Command("tasklist","/FI", "PID eq " + strconv.Itoa(pid)).Output()
output := string(cmd[:])
splitOutp := strings.Split(output, " ")
if !(splitOutp[1] == "no") {
time.Sleep(500 * time.Millisecond)
fmt.Println("Process is running...")
CheckProcessLife(pid)
}else{
fmt.Println("Process is no longer running.")
}
}
You can check if the process is running with his PID or directly with his name, only change this line:
cmd,_ := exec.Command("tasklist","/FI", "IMAGENAME eq yourprocessname.exe").Output()
Upvotes: -1
Reputation: 605
All the answers so far are incomplete implementations. See https://github.com/shirou/gopsutil/blob/c141152a7b8f59b63e060fa8450f5cd5e7196dfb/process/process_posix.go#L73 for a more complete implementation (copied inline)
func PidExists(pid int32) (bool, error) {
if pid <= 0 {
return false, fmt.Errorf("invalid pid %v", pid)
}
proc, err := os.FindProcess(int(pid))
if err != nil {
return false, err
}
err = proc.Signal(syscall.Signal(0))
if err == nil {
return true, nil
}
if err.Error() == "os: process already finished" {
return false, nil
}
errno, ok := err.(syscall.Errno)
if !ok {
return false, err
}
switch errno {
case syscall.ESRCH:
return false, nil
case syscall.EPERM:
return true, nil
}
return false, err
}
Upvotes: 4
Reputation: 676
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
}
Upvotes: 2
Reputation: 2497
You can also just use syscall.Kill
. It amounts to less code.
killErr := syscall.Kill(pid, syscall.Signal(0))
procExists := killErr == nil
Upvotes: 5
Reputation: 62777
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):
Upvotes: 2
Reputation: 54079
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\n", err)
} else {
err := process.Signal(syscall.Signal(0))
fmt.Printf("process.Signal on pid %d returned: %v\n", 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
Upvotes: 48
Reputation: 53398
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.
Upvotes: 6