diff options
author | Justin M. Keyes <justinkz@gmail.com> | 2018-03-11 21:46:14 +0100 |
---|---|---|
committer | Justin M. Keyes <justinkz@gmail.com> | 2018-03-16 10:55:12 +0100 |
commit | de86f824835b1556cc0070dd5720cdae484a0296 (patch) | |
tree | 8c37fd5de913b92f55a6bb597bd89788bac7ea08 | |
parent | 8d90171f8be6b92d7186ca84c42a0e07c2c71908 (diff) | |
download | rneovim-de86f824835b1556cc0070dd5720cdae484a0296.tar.gz rneovim-de86f824835b1556cc0070dd5720cdae484a0296.tar.bz2 rneovim-de86f824835b1556cc0070dd5720cdae484a0296.zip |
win: os_proc_tree_kill()
XXX: comment at https://stackoverflow.com/q/1173342 :
> Windows recycles PIDs quite fast, you have to be extra careful not
> to kill unrelated processes. These APIs will report PPIDs for long
> dead processes whose PIDs may have been recycled. Check the parent
> start date to make sure it is related to the processes you spawned.
-rw-r--r-- | src/nvim/event/process.c | 18 | ||||
-rw-r--r-- | src/nvim/os/process.c | 87 | ||||
-rw-r--r-- | src/nvim/os/process.h | 8 |
3 files changed, 96 insertions, 17 deletions
diff --git a/src/nvim/event/process.c b/src/nvim/event/process.c index 78ef253d8b..60650344ce 100644 --- a/src/nvim/event/process.c +++ b/src/nvim/event/process.c @@ -12,6 +12,7 @@ #include "nvim/event/wstream.h" #include "nvim/event/process.h" #include "nvim/event/libuv_process.h" +#include "nvim/os/process.h" #include "nvim/os/pty_process.h" #include "nvim/globals.h" #include "nvim/macros.h" @@ -201,23 +202,6 @@ int process_wait(Process *proc, int ms, MultiQueue *events) return proc->status; } -/// Kills a process and its descendants. -static void os_proc_tree_kill(int pid, int sig) { - assert(sig == SIGTERM || sig == SIGKILL); - int pgid = getpgid(pid); - if (pgid > 0) { // Ignore error. Never kill self (pid=0). - if (pgid == pid) { - ILOG("sending %s to process group: -%d", - sig == SIGTERM ? "SIGTERM" : "SIGKILL", - pgid); - uv_kill(-pgid, sig); - } else { - // Should never happen, because process_spawn() did setsid() in the child. - ELOG("pgid %d != pid %d", pgid, pid); - } - } -} - /// Ask a process to terminate and eventually kill if it doesn't respond void process_stop(Process *proc) FUNC_ATTR_NONNULL_ALL { diff --git a/src/nvim/os/process.c b/src/nvim/os/process.c new file mode 100644 index 0000000000..eefc94faf6 --- /dev/null +++ b/src/nvim/os/process.c @@ -0,0 +1,87 @@ +// This is an open source non-commercial project. Dear PVS-Studio, please check +// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com + +#include <uv.h> // for HANDLE (win32) +#ifdef WIN32 +# include <tlhelp32.h> // for CreateToolhelp32Snapshot +#endif + +#include "nvim/log.h" +#include "nvim/os/process.h" +#include "nvim/os/os.h" +#include "nvim/os/os_defs.h" + +#ifdef INCLUDE_GENERATED_DECLARATIONS +# include "os/process.c.generated.h" +#endif + +#ifdef WIN32 +/// Kills process `pid` and its descendants recursively. +bool os_proc_tree_kill_rec(HANDLE process, int sig) +{ + if (process == NULL) { + return false; + } + PROCESSENTRY32 pe; + DWORD pid = GetProcessId(process); + + if (pid != 0) { + HANDLE h = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); + if (h != INVALID_HANDLE_VALUE) { + pe.dwSize = sizeof(PROCESSENTRY32); + if (!Process32First(h, &pe)) { + goto theend; + } + + do { + if (pe.th32ParentProcessID == pid) { + HANDLE ph = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pe.th32ProcessID); + if (ph != NULL) { + os_proc_tree_kill_rec(ph, sig); + CloseHandle(ph); + } + } + } while (Process32Next(h, &pe)); + + CloseHandle(h); + } + } + +theend: + return (bool)TerminateProcess(process, (unsigned int)sig); +} +bool os_proc_tree_kill(int pid, int sig) +{ + assert(sig >= 0); + assert(sig == SIGTERM || sig == SIGKILL); + if (pid > 0) { + ILOG("terminating process tree: %d", pid); + HANDLE h = OpenProcess(PROCESS_ALL_ACCESS, FALSE, (DWORD)pid); + return os_proc_tree_kill_rec(h, sig); + } else { + ELOG("invalid pid: %d", pid); + } + return false; +} +#else +/// Kills process group where `pid` is the process group leader. +bool os_proc_tree_kill(int pid, int sig) +{ + assert(sig == SIGTERM || sig == SIGKILL); + int pgid = getpgid(pid); + if (pgid > 0) { // Ignore error. Never kill self (pid=0). + if (pgid == pid) { + ILOG("sending %s to process group: -%d", + sig == SIGTERM ? "SIGTERM" : "SIGKILL", pgid); + int rv = uv_kill(-pgid, sig); + return rv == 0; + } else { + // Should never happen, because process_spawn() did setsid() in the child. + ELOG("pgid %d != pid %d", pgid, pid); + } + } else { + ELOG("getpgid(%d) returned %d", pid, pgid); + } + return false; +} +#endif diff --git a/src/nvim/os/process.h b/src/nvim/os/process.h new file mode 100644 index 0000000000..9549ae9081 --- /dev/null +++ b/src/nvim/os/process.h @@ -0,0 +1,8 @@ +#ifndef NVIM_OS_PROCESS_H +#define NVIM_OS_PROCESS_H + +#ifdef INCLUDE_GENERATED_DECLARATIONS +# include "os/process.h.generated.h" +#endif + +#endif // NVIM_OS_PROCESS_H |