summaryrefslogtreecommitdiffstats
path: root/vendor
diff options
context:
space:
mode:
authorJesse Duffield <jessedduffield@gmail.com>2022-06-18 13:28:20 +1000
committerJesse Duffield <jessedduffield@gmail.com>2022-06-18 13:39:22 +1000
commitc9d891a91366cfcd3481904fd6a0311166cd2696 (patch)
treed708f80bb2153128c26e551706110254ba172bf4 /vendor
parenta5821f5ec83374de5f66a392556bf522a217c092 (diff)
better process killing
Diffstat (limited to 'vendor')
-rw-r--r--vendor/github.com/jesseduffield/kill/LICENSE21
-rw-r--r--vendor/github.com/jesseduffield/kill/README.md3
-rw-r--r--vendor/github.com/jesseduffield/kill/kill_default_platform.go33
-rw-r--r--vendor/github.com/jesseduffield/kill/kill_windows.go136
-rw-r--r--vendor/modules.txt3
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