Windows と Linux それぞれで、どうやってプロセスの存在確認を行うかというのをやっていく。
今回使用するのは syscall
パッケージ。
プロジェクト作成
go mod init
で作成。
go mod init github.com/mikoto2000/TIL/golang/process/isExists/syscall
実装
サードパーティーのライブラリは使っていないので、そのまま実装に進む。
Go 言語はビルドタグを使うことで、環境変数応じてビルドするかしないかを、ファイルごとに定義することができる。(See: Goのビルドタグの書き方が// +buildから//go:buildに変わった理由)
この仕組みを利用して、 Windows 版の処理と Linux 版の処理を書き分けていく。
説明を記載する体力がなくなったので、各 API の詳細は参考資料のリンク先を参照してくださいで済ませます。
Windows
版の処理(process_windows.go
)
//go:build windows
package main
import (
"os"
"syscall"
)
func IsRunningProcess(process *os.Process) (bool, error) {
const PROCESS_QUERY_LIMITED_INFORMATION = 0x1000
, err := syscall.OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, false, uint32(process.Pid))
handleif err != nil {
// そもそもチェック処理で失敗
return false, err
}
defer syscall.CloseHandle(handle)
var exitCode uint32
= syscall.GetExitCodeProcess(handle, &exitCode)
err if err != nil {
// そもそもチェック処理で失敗
return false, err
}
if exitCode == 259 { // STILL_ACTIVE
// プロセスが実行中
return true, nil
} else {
// プロセスが実行中でない
return false, nil
}
}
Linux
版の処理(process_nowindows.go
)
//go:build !windows
package main
import (
"os"
"syscall"
)
func IsRunningProcess(process *os.Process) (bool, error) {
:= process.Signal(syscall.Signal(0))
err if err != nil {
if err == os.ErrProcessDone {
// プロセスが存在していない
return false, nil
} else {
// そもそもチェック処理で失敗
return false, err
}
} else {
// プロセスが既に存在している
return true, nil
}
}
メイン関数(main.go
)
package main
import (
"log"
"os"
"strconv"
)
/**
* コマンドライン引数のひとつ目に PID をうけとり、
* その PID のプロセスが実行中かを表示する。
*/
func main() {
:= os.Args[1]
pidString .Printf("PID String: %s", pidString)
log
, err := strconv.Atoi(pidString)
pidif err != nil {
.Fatal(err)
log}
.Printf("PID Decimal: %d", pid)
log
// プロセスを取得
, err := os.FindProcess(pid)
processif err != nil {
// そもそも PID が割り当てられたことが無い(Windows)
// Linux では必ず成功するので後段のチェックが必須
.Printf("PID %d は実行していません。\n", pid)
log.Exit(0)
os}
.Printf("PID from Process type: %d", process.Pid)
log
// プロセスを渡してプロセスが実行中かを確認
// (ビルドフラグによって windows とそれ以外で処理を分けている)
, err := IsRunningProcess(process)
isRunningif err != nil {
.Fatal(err)
log}
// 表示
if isRunning {
.Printf("PID %d は実行中です。\n", pid)
log} else {
.Printf("PID %d は実行していません。\n", pid)
log}
}
動作確認
Windows
試しに gvim
を起動して、それが実行中かを確認するとの、適当な PID
を入れて実行されていないのを確認する。
> $(Get-Process -Name gvim).Id
30084
> .\syscall.exe 30084
2024/05/30 17:49:29 PID String: 30084
2024/05/30 17:49:29 PID Decimal: 30084
2024/05/30 17:49:29 PID from Process type: 30084
2024/05/30 17:49:29 PID 30084 は実行中です。
> .\syscall.exe 99999999
2024/05/30 17:49:34 PID String: 99999999
2024/05/30 17:49:34 PID Decimal: 99999999
2024/05/30 17:49:34 PID 99999999 は実行していません。
OK そう。
Linux
試しに自分の bash
が実行中かを確認するとの、適当な PID
を入れて実行されていないのを確認する。
$ ps
PID TTY TIME CMD
208144 pts/12 00:00:00 bash
221983 pts/12 00:00:00 ps
$ ./syscall 208144
2024/05/30 17:53:14 PID String: 208144
2024/05/30 17:53:14 PID Decimal: 208144
2024/05/30 17:53:14 PID from Process type: 208144
2024/05/30 17:53:14 PID 208144 は実行中です。
$ ./syscall 999999
2024/05/30 17:53:20 PID String: 999999
2024/05/30 17:53:20 PID Decimal: 999999
2024/05/30 17:53:20 PID from Process type: 999999
2024/05/30 17:53:20 PID 999999 は実行していません。
こちらも OK そう。
以上。
補足
ツイッターにて以下コメントをもらったので、この後そちらも試す予定。
gopsutil を使うとちょっと統一できるかもです。https://t.co/kwvbnbUOko
— mattn (@mattn_jp) May 30, 2024
参考資料
- 共通
- Linux
- Windows
- L264(OpenProcess) - syyscall_windows.go - The Go Programming Language
- OpenProcess 関数 (processthreadsapi.h) - Win32 apps | Microsoft Learn
- OpenProcess の第二引数(dwDesiredAccess) - セキュリティとアクセス権の処理 - Win32 apps | Microsoft Learn
- L266(GetExitCodeProcess) - syyscall_windows.go - The Go Programming Language
- GetExitCodeProcess 関数 (processthreadsapi.h) - Win32 apps | Microsoft Learn
0 件のコメント:
コメントを投稿