Allow skipping kill_process_tree().
authorIain Patterson <me@iain.cx>
Sat, 13 Sep 2014 07:01:18 +0000 (08:01 +0100)
committerIain Patterson <me@iain.cx>
Sat, 13 Sep 2014 07:01:18 +0000 (08:01 +0100)
Don't try to kill the application's process tree - just the application
itself - if the REG_DWORD value AppKillProcessTree is 0.

Thanks Barrett Lewis.

ChangeLog.txt
README.txt
gui.cpp
nssm.rc
registry.cpp
registry.h
resource.h
service.cpp
service.h
settings.cpp

index 987fe1e..6d127fc 100644 (file)
@@ -1,3 +1,7 @@
+Changes since 2.24\r
+------------------\r
+  * Allow skipping kill_process_tree().\r
+\r
 Changes since 2.23\r
 ------------------\r
   * NSSM once again calls TerminateProcess() correctly.\r
index 7fcb85b..7aca940 100644 (file)
@@ -261,6 +261,11 @@ that the timeout applies to each process in the application's process tree,
 so the actual time to shutdown may be longer than the sum of all configured\r
 timeouts if the application spawns multiple subprocesses.\r
 \r
+To skip applying the above stop methods to all processes in the application's\r
+process tree, applying them only to the original application process, set the\r
+HKLM\SYSTEM\CurrentControlSet\Services\<service>\Parameters\AppKillProcessTree\r
+registry value, which should be of type REG_DWORD, to 0.\r
+\r
 \r
 Console window\r
 --------------\r
@@ -685,6 +690,8 @@ Thanks to Hadrien Kohl for suggesting to disable the console window's menu.
 Thanks to Allen Vailliencourt for noticing bugs with configuring the service to\r
 run under a local user account.\r
 Thanks to Sam Townsend for noticing a regression with TerminateProcess().\r
+Thanks to Barrett Lewis for suggesting the option to skip terminating the\r
+application's child processes.\r
 \r
 Licence\r
 -------\r
diff --git a/gui.cpp b/gui.cpp
index 692fb9b..d85e9c0 100644 (file)
--- a/gui.cpp
+++ b/gui.cpp
@@ -153,6 +153,9 @@ int nssm_gui(int resource, nssm_service_t *service) {
     if (! (service->stop_method & NSSM_STOP_METHOD_TERMINATE)) {\r
       SendDlgItemMessage(tablist[NSSM_TAB_SHUTDOWN], IDC_METHOD_TERMINATE, BM_SETCHECK, BST_UNCHECKED, 0);\r
     }\r
+    if (! service->kill_process_tree) {\r
+      SendDlgItemMessage(tablist[NSSM_TAB_SHUTDOWN], IDC_KILL_PROCESS_TREE, BM_SETCHECK, BST_UNCHECKED, 0);\r
+    }\r
 \r
     /* Restart tab. */\r
     SetDlgItemInt(tablist[NSSM_TAB_EXIT], IDC_THROTTLE, service->throttle_delay, 0);\r
@@ -545,6 +548,8 @@ int configure(HWND window, nssm_service_t *service, nssm_service_t *orig_service
   check_number(tablist[NSSM_TAB_SHUTDOWN], IDC_KILL_CONSOLE, &service->kill_console_delay);\r
   check_number(tablist[NSSM_TAB_SHUTDOWN], IDC_KILL_WINDOW, &service->kill_window_delay);\r
   check_number(tablist[NSSM_TAB_SHUTDOWN], IDC_KILL_THREADS, &service->kill_threads_delay);\r
+  if (SendDlgItemMessage(tablist[NSSM_TAB_SHUTDOWN], IDC_KILL_PROCESS_TREE, BM_GETCHECK, 0, 0) & BST_CHECKED) service->kill_process_tree = 1;\r
+  else service->kill_process_tree = 0;\r
 \r
   /* Get exit action stuff. */\r
   check_number(tablist[NSSM_TAB_EXIT], IDC_THROTTLE, &service->throttle_delay);\r
@@ -1070,6 +1075,7 @@ INT_PTR CALLBACK nssm_dlg(HWND window, UINT message, WPARAM w, LPARAM l) {
       SendDlgItemMessage(tablist[NSSM_TAB_SHUTDOWN], IDC_METHOD_THREADS, BM_SETCHECK, BST_CHECKED, 0);\r
       SetDlgItemInt(tablist[NSSM_TAB_SHUTDOWN], IDC_KILL_THREADS, NSSM_KILL_THREADS_GRACE_PERIOD, 0);\r
       SendDlgItemMessage(tablist[NSSM_TAB_SHUTDOWN], IDC_METHOD_TERMINATE, BM_SETCHECK, BST_CHECKED, 0);\r
+      SendDlgItemMessage(tablist[NSSM_TAB_SHUTDOWN], IDC_KILL_PROCESS_TREE, BM_SETCHECK, BST_CHECKED, 1);\r
 \r
       /* Restart tab. */\r
       tab.pszText = message_string(NSSM_GUI_TAB_EXIT);\r
diff --git a/nssm.rc b/nssm.rc
index 2d13624..c0886e3 100644 (file)
Binary files a/nssm.rc and b/nssm.rc differ
index 6c1567c..bf2ddc5 100644 (file)
@@ -79,6 +79,8 @@ int create_parameters(nssm_service_t *service, bool editing) {
   else if (editing) RegDeleteValue(key, NSSM_REG_KILL_WINDOW_GRACE_PERIOD);\r
   if (service->kill_threads_delay != NSSM_KILL_THREADS_GRACE_PERIOD) set_number(key, NSSM_REG_KILL_THREADS_GRACE_PERIOD, service->kill_threads_delay);\r
   else if (editing) RegDeleteValue(key, NSSM_REG_KILL_THREADS_GRACE_PERIOD);\r
+  if (! service->kill_process_tree) set_number(key, NSSM_REG_KILL_PROCESS_TREE, 0);\r
+  else if (editing) RegDeleteValue(key, NSSM_REG_KILL_PROCESS_TREE);\r
   if (service->stdin_path[0] || editing) {\r
     if (service->stdin_path[0]) set_expand_string(key, NSSM_REG_STDIN, service->stdin_path);\r
     else if (editing) RegDeleteValue(key, NSSM_REG_STDIN);\r
@@ -649,6 +651,14 @@ int get_parameters(nssm_service_t *service, STARTUPINFO *si) {
   override_milliseconds(service->name, key, NSSM_REG_KILL_WINDOW_GRACE_PERIOD, &service->kill_window_delay, NSSM_KILL_WINDOW_GRACE_PERIOD, NSSM_EVENT_BOGUS_KILL_WINDOW_GRACE_PERIOD);\r
   override_milliseconds(service->name, key, NSSM_REG_KILL_THREADS_GRACE_PERIOD, &service->kill_threads_delay, NSSM_KILL_THREADS_GRACE_PERIOD, NSSM_EVENT_BOGUS_KILL_THREADS_GRACE_PERIOD);\r
 \r
+  /* Try to get process tree settings - may fail. */\r
+  unsigned long kill_process_tree;\r
+  if (get_number(key, NSSM_REG_KILL_PROCESS_TREE, &kill_process_tree, false) == 1) {\r
+    if (kill_process_tree) service->kill_process_tree = true;\r
+    else service->kill_process_tree = false;\r
+  }\r
+  else service->kill_process_tree = true;\r
+\r
   /* Try to get default exit action. */\r
   bool default_action;\r
   service->default_exit_action = NSSM_EXIT_RESTART;\r
index 7bf49b0..f831f89 100644 (file)
@@ -16,6 +16,7 @@
 #define NSSM_REG_KILL_CONSOLE_GRACE_PERIOD _T("AppStopMethodConsole")\r
 #define NSSM_REG_KILL_WINDOW_GRACE_PERIOD _T("AppStopMethodWindow")\r
 #define NSSM_REG_KILL_THREADS_GRACE_PERIOD _T("AppStopMethodThreads")\r
+#define NSSM_REG_KILL_PROCESS_TREE _T("AppKillProcessTree")\r
 #define NSSM_REG_STDIN _T("AppStdin")\r
 #define NSSM_REG_STDOUT _T("AppStdout")\r
 #define NSSM_REG_STDERR _T("AppStderr")\r
index 36477aa..1b89da8 100644 (file)
@@ -64,6 +64,7 @@
 #define IDC_AFFINITY                    1044\r
 #define IDC_CONSOLE                     1045\r
 #define IDC_DEPENDENCIES                1046\r
+#define IDC_KILL_PROCESS_TREE           1047\r
 \r
 // Next default values for new objects\r
 // \r
@@ -71,7 +72,7 @@
 #ifndef APSTUDIO_READONLY_SYMBOLS\r
 #define _APS_NEXT_RESOURCE_VALUE        115\r
 #define _APS_NEXT_COMMAND_VALUE         40001\r
-#define _APS_NEXT_CONTROL_VALUE         1047\r
+#define _APS_NEXT_CONTROL_VALUE         1048\r
 #define _APS_NEXT_SYMED_VALUE           101\r
 #endif\r
 #endif\r
index 3d3acb9..52937cf 100644 (file)
@@ -689,6 +689,7 @@ void set_nssm_service_defaults(nssm_service_t *service) {
   service->kill_console_delay = NSSM_KILL_CONSOLE_GRACE_PERIOD;\r
   service->kill_window_delay = NSSM_KILL_WINDOW_GRACE_PERIOD;\r
   service->kill_threads_delay = NSSM_KILL_THREADS_GRACE_PERIOD;\r
+  service->kill_process_tree = 1;\r
 }\r
 \r
 /* Allocate and zero memory for a service. */\r
@@ -1800,7 +1801,7 @@ void CALLBACK end_service(void *arg, unsigned char why) {
 \r
   /* Clean up. */\r
   if (exitcode == STILL_ACTIVE) exitcode = 0;\r
-  if (service->pid) kill_process_tree(service, service->pid, exitcode, service->pid);\r
+  if (service->pid && service->kill_process_tree) kill_process_tree(service, service->pid, exitcode, service->pid);\r
   service->pid = 0;\r
 \r
   /*\r
index 9208b2e..dd96f7c 100644 (file)
--- a/service.h
+++ b/service.h
@@ -84,6 +84,7 @@ typedef struct {
   unsigned long kill_console_delay;\r
   unsigned long kill_window_delay;\r
   unsigned long kill_threads_delay;\r
+  bool kill_process_tree;\r
   SC_HANDLE handle;\r
   SERVICE_STATUS status;\r
   SERVICE_STATUS_HANDLE status_handle;\r
index 14b279a..0ed75ee 100644 (file)
@@ -1042,6 +1042,7 @@ settings_t settings[] = {
   { NSSM_REG_KILL_CONSOLE_GRACE_PERIOD, REG_DWORD, (void *) NSSM_KILL_CONSOLE_GRACE_PERIOD, false, 0, setting_set_number, setting_get_number },
   { NSSM_REG_KILL_WINDOW_GRACE_PERIOD, REG_DWORD, (void *) NSSM_KILL_WINDOW_GRACE_PERIOD, false, 0, setting_set_number, setting_get_number },
   { NSSM_REG_KILL_THREADS_GRACE_PERIOD, REG_DWORD, (void *) NSSM_KILL_THREADS_GRACE_PERIOD, false, 0, setting_set_number, setting_get_number },
+  { NSSM_REG_KILL_PROCESS_TREE, REG_DWORD, (void *) 1, false, 0, setting_set_number, setting_get_number },
   { NSSM_REG_THROTTLE, REG_DWORD, (void *) NSSM_RESET_THROTTLE_RESTART, false, 0, setting_set_number, setting_get_number },
   { NSSM_REG_ROTATE, REG_DWORD, 0, false, 0, setting_set_number, setting_get_number },
   { NSSM_REG_ROTATE_ONLINE, REG_DWORD, 0, false, 0, setting_set_number, setting_get_number },