diff options
author | Jesse Duffield <jessedduffield@gmail.com> | 2022-06-18 13:28:20 +1000 |
---|---|---|
committer | Jesse Duffield <jessedduffield@gmail.com> | 2022-06-18 13:39:22 +1000 |
commit | c9d891a91366cfcd3481904fd6a0311166cd2696 (patch) | |
tree | d708f80bb2153128c26e551706110254ba172bf4 /vendor | |
parent | a5821f5ec83374de5f66a392556bf522a217c092 (diff) |
better process killing
Diffstat (limited to 'vendor')
-rw-r--r-- | vendor/github.com/jesseduffield/kill/LICENSE | 21 | ||||
-rw-r--r-- | vendor/github.com/jesseduffield/kill/README.md | 3 | ||||
-rw-r--r-- | vendor/github.com/jesseduffield/kill/kill_default_platform.go | 33 | ||||
-rw-r--r-- | vendor/github.com/jesseduffield/kill/kill_windows.go | 136 | ||||
-rw-r--r-- | vendor/modules.txt | 3 |
5 files changed, 196 insertions, 0 deletions
diff --git a/vendor/github.com/jesseduffield/kill/LICENSE b/vendor/github.com/jesseduffield/kill/LICENSE new file mode 100644 index 000000000..2a7175dcc --- /dev/null +++ b/vendor/github.com/jesseduffield/kill/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 Jesse Duffield + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/jesseduffield/kill/README.md b/vendor/github.com/jesseduffield/kill/README.md new file mode 100644 index 000000000..75ca05db4 --- /dev/null +++ b/vendor/github.com/jesseduffield/kill/README.md @@ -0,0 +1,3 @@ +# Kill + +Go package for killing processes across different platforms. Handles killing children of processes as well as the process itself. diff --git a/vendor/github.com/jesseduffield/kill/kill_default_platform.go b/vendor/github.com/jesseduffield/kill/kill_default_platform.go new file mode 100644 index 000000000..6fb5a313a --- /dev/null +++ b/vendor/github.com/jesseduffield/kill/kill_default_platform.go @@ -0,0 +1,33 @@ +//go:build !windows +// +build !windows + +package kill + +import ( + "os/exec" + "syscall" +) + +// Kill kills a process. If the process has Setpgid == true, then we have anticipated that it might spawn its own child processes, so we've given it a process group ID (PGID) equal to its process id (PID) and given its child processes will inherit the PGID, we can kill that group, rather than killing the process itself. +func Kill(cmd *exec.Cmd) error { + if cmd.Process == nil { + // You can't kill a person with no body + return nil + } + + if cmd.SysProcAttr != nil && cmd.SysProcAttr.Setpgid { + // minus sign means we're talking about a PGID as opposed to a PID + return syscall.Kill(-cmd.Process.Pid, syscall.SIGKILL) + } + + return cmd.Process.Kill() +} + +// PrepareForChildren ensures that child processes of this parent process will share the same group id +// as the parent, meaning when the call Kill on the parent process, we'll kill +// the whole group, parent and children both. Gruesome when you think about it. +func PrepareForChildren(cmd *exec.Cmd) { + cmd.SysProcAttr = &syscall.SysProcAttr{ + Setpgid: true, + } +} diff --git a/vendor/github.com/jesseduffield/kill/kill_windows.go b/vendor/github.com/jesseduffield/kill/kill_windows.go new file mode 100644 index 000000000..1ac08a125 --- /dev/null +++ b/vendor/github.com/jesseduffield/kill/kill_windows.go @@ -0,0 +1,136 @@ +// adapted from https://blog.csdn.net/fyxichen/article/details/51857864 + +package kill + +import ( + "os" + "os/exec" + "syscall" + "unsafe" +) + +// Kill kills a process, along with any child processes it may have spawned. +func Kill(cmd *exec.Cmd) error { + if cmd.Process == nil { + // You can't kill a person with no body + return nil + } + + pids := Getppids(uint32(cmd.Process.Pid)) + for _, pid := range pids { + pro, err := os.FindProcess(int(pid)) + if err != nil { + continue + } + + pro.Kill() + } + + return nil +} + +// PrepareForChildren ensures that child processes of this parent process will share the same group id +// as the parent, meaning when the call Kill on the parent process, we'll kill +// the whole group, parent and children both. Gruesome when you think about it. +func PrepareForChildren(cmd *exec.Cmd) { + // do nothing because on windows our Kill function handles children by default. +} + +const ( + MAX_PATH = 260 + TH32CS_SNAPPROCESS = 0x00000002 +) + +type ProcessInfo struct { + Name string + Pid uint32 + PPid uint32 +} + +type PROCESSENTRY32 struct { + DwSize uint32 + CntUsage uint32 + Th32ProcessID uint32 + Th32DefaultHeapID uintptr + Th32ModuleID uint32 + CntThreads uint32 + Th32ParentProcessID uint32 + PcPriClassBase int32 + DwFlags uint32 + SzExeFile [MAX_PATH]uint16 +} + +type HANDLE uintptr + +var ( + modkernel32 = syscall.NewLazyDLL("kernel32.dll") + procCreateToolhelp32Snapshot = modkernel32.NewProc("CreateToolhelp32Snapshot") + procProcess32First = modkernel32.NewProc("Process32FirstW") + procProcess32Next = modkernel32.NewProc("Process32NextW") + procCloseHandle = modkernel32.NewProc("CloseHandle") +) + +func Getppids(pid uint32) []uint32 { + infos, err := GetProcs() + if err != nil { + return []uint32{pid} + } + var pids []uint32 = make([]uint32, 0, len(infos)) + var index int = 0 + pids = append(pids, pid) + + var length int = len(pids) + for index < length { + for _, info := range infos { + if info.PPid == pids[index] { + pids = append(pids, info.Pid) + } + } + index += 1 + length = len(pids) + } + return pids +} + +func GetProcs() (procs []ProcessInfo, err error) { + snap := createToolhelp32Snapshot(TH32CS_SNAPPROCESS, uint32(0)) + if snap == 0 { + err = syscall.GetLastError() + return + } + defer closeHandle(snap) + var pe32 PROCESSENTRY32 + pe32.DwSize = uint32(unsafe.Sizeof(pe32)) + if process32First(snap, &pe32) == false { + err = syscall.GetLastError() + return + } + procs = append(procs, ProcessInfo{syscall.UTF16ToString(pe32.SzExeFile[:260]), pe32.Th32ProcessID, pe32.Th32ParentProcessID}) + for process32Next(snap, &pe32) { + procs = append(procs, ProcessInfo{syscall.UTF16ToString(pe32.SzExeFile[:260]), pe32.Th32ProcessID, pe32.Th32ParentProcessID}) + } + return +} + +func createToolhelp32Snapshot(flags, processId uint32) HANDLE { + ret, _, _ := procCreateToolhelp32Snapshot.Call(uintptr(flags), uintptr(processId)) + if ret <= 0 { + return HANDLE(0) + } + return HANDLE(ret) +} + +func process32First(snapshot HANDLE, pe *PROCESSENTRY32) bool { + ret, _, _ := procProcess32First.Call(uintptr(snapshot), uintptr(unsafe.Pointer(pe))) + return ret != 0 +} + +func process32Next(snapshot HANDLE, pe *PROCESSENTRY32) bool { + ret, _, _ := procProcess32Next.Call(uintptr(snapshot), uintptr(unsafe.Pointer(pe))) + return ret != 0 +} + +func closeHandle(object HANDLE) bool { + ret, _, _ := procCloseHandle.Call(uintptr(object)) + return ret != 0 +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 14915d4da..07d49b414 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -175,6 +175,9 @@ github.com/jesseduffield/go-git/v5/utils/merkletrie/noder # github.com/jesseduffield/gocui v0.3.1-0.20220417002912-bce22fd599f6 ## explicit; go 1.12 github.com/jesseduffield/gocui +# github.com/jesseduffield/kill v0.0.0-20220618033138-bfbe04675d10 +## explicit; go 1.18 +github.com/jesseduffield/kill # github.com/jesseduffield/minimal/gitignore v0.3.3-0.20211018110810-9cde264e6b1e ## explicit; go 1.15 github.com/jesseduffield/minimal/gitignore |