Kill process tree from the top down.
authorIain Patterson <me@iain.cx>
Mon, 27 Jan 2014 22:21:15 +0000 (22:21 +0000)
committerIain Patterson <me@iain.cx>
Mon, 27 Jan 2014 22:34:17 +0000 (22:34 +0000)
On Windows 8.1 (and maybe other versions), attempting to kill
conhost.exe before its parent cmd.exe will cause the attempt to kill the
latter to fail and the console window to remain active after the service
ends.

We now kill the members of the process tree in reverse order, so the
problem doesn't occur.

Thanks Czenda Czendov.

README.txt
process.cpp

index edddf04..de01aa4 100644 (file)
@@ -663,6 +663,7 @@ affinity support.
 Thanks to Andrew RedzMax for suggesting an unconditional restart delay.\r
 Thanks to Bryan Senseman for noticing that applications with redirected stdout\r
 and/or stderr which attempt to read from stdin would fail.\r
+Thanks to Czenda Czendov for help with Visual Studio 2013 and Server 2012R2.\r
 \r
 Licence\r
 -------\r
index c0b65df..daeeea7 100644 (file)
@@ -251,6 +251,26 @@ void kill_process_tree(nssm_service_t *service, unsigned long pid, unsigned long
   _sntprintf_s(code, _countof(code), _TRUNCATE, _T("%lu"), exitcode);
   log_event(EVENTLOG_INFORMATION_TYPE, NSSM_EVENT_KILLING, service->name, pid_string, code, 0);
 
+  /* We will need a process handle in order to call TerminateProcess() later. */
+  HANDLE process_handle = OpenProcess(SYNCHRONIZE | PROCESS_QUERY_INFORMATION | PROCESS_VM_READ | PROCESS_TERMINATE, false, pid);
+  if (process_handle) {
+    /* Kill this process first, then its descendents. */
+    TCHAR ppid_string[16];
+    _sntprintf_s(ppid_string, _countof(ppid_string), _TRUNCATE, _T("%lu"), ppid);
+    log_event(EVENTLOG_INFORMATION_TYPE, NSSM_EVENT_KILL_PROCESS_TREE, pid_string, ppid_string, service->name, 0);
+    if (! kill_process(service, process_handle, pid, exitcode)) {
+      /* Maybe it already died. */
+      unsigned long ret;
+      if (! GetExitCodeProcess(process_handle, &ret) || ret == STILL_ACTIVE) {
+        if (service->stop_method & NSSM_STOP_METHOD_TERMINATE) log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_TERMINATEPROCESS_FAILED, pid_string, service->name, error_string(GetLastError()), 0);
+        else log_event(EVENTLOG_WARNING_TYPE, NSSM_EVENT_PROCESS_STILL_ACTIVE, service->name, pid_string, NSSM, NSSM_REG_STOP_METHOD_SKIP, 0);
+      }
+    }
+
+    CloseHandle(process_handle);
+  }
+  else log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OPENPROCESS_FAILED, pid_string, service->name, error_string(GetLastError()), 0);
+
   /* Get a snapshot of all processes in the system. */
   HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
   if (! snapshot) {
@@ -285,25 +305,4 @@ void kill_process_tree(nssm_service_t *service, unsigned long pid, unsigned long
   }
 
   CloseHandle(snapshot);
-
-  /* We will need a process handle in order to call TerminateProcess() later. */
-  HANDLE process_handle = OpenProcess(SYNCHRONIZE | PROCESS_QUERY_INFORMATION | PROCESS_VM_READ | PROCESS_TERMINATE, false, pid);
-  if (! process_handle) {
-    log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OPENPROCESS_FAILED, pid_string, service->name, error_string(GetLastError()), 0);
-    return;
-  }
-
-  TCHAR ppid_string[16];
-  _sntprintf_s(ppid_string, _countof(ppid_string), _TRUNCATE, _T("%lu"), ppid);
-  log_event(EVENTLOG_INFORMATION_TYPE, NSSM_EVENT_KILL_PROCESS_TREE, pid_string, ppid_string, service->name, 0);
-  if (! kill_process(service, process_handle, pid, exitcode)) {
-    /* Maybe it already died. */
-    unsigned long ret;
-    if (! GetExitCodeProcess(process_handle, &ret) || ret == STILL_ACTIVE) {
-      if (service->stop_method & NSSM_STOP_METHOD_TERMINATE) log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_TERMINATEPROCESS_FAILED, pid_string, service->name, error_string(GetLastError()), 0);
-      else log_event(EVENTLOG_WARNING_TYPE, NSSM_EVENT_PROCESS_STILL_ACTIVE, service->name, pid_string, NSSM, NSSM_REG_STOP_METHOD_SKIP, 0);
-    }
-  }
-
-  CloseHandle(process_handle);
 }