aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJustin M. Keyes <justinkz@gmail.com>2018-03-11 21:46:14 +0100
committerJustin M. Keyes <justinkz@gmail.com>2018-03-16 10:55:12 +0100
commitde86f824835b1556cc0070dd5720cdae484a0296 (patch)
tree8c37fd5de913b92f55a6bb597bd89788bac7ea08
parent8d90171f8be6b92d7186ca84c42a0e07c2c71908 (diff)
downloadrneovim-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.c18
-rw-r--r--src/nvim/os/process.c87
-rw-r--r--src/nvim/os/process.h8
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