Browse Source

Allow skipping kill_process_tree().

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.
Iain Patterson 7 years ago
parent
commit
b5286398f8
10 changed files with 34 additions and 2 deletions
  1. 4 0
      ChangeLog.txt
  2. 7 0
      README.txt
  3. 6 0
      gui.cpp
  4. BIN
      nssm.rc
  5. 10 0
      registry.cpp
  6. 1 0
      registry.h
  7. 2 1
      resource.h
  8. 2 1
      service.cpp
  9. 1 0
      service.h
  10. 1 0
      settings.cpp

+ 4 - 0
ChangeLog.txt

@@ -1,3 +1,7 @@
+Changes since 2.24
+------------------
+  * Allow skipping kill_process_tree().
+
 Changes since 2.23
 ------------------
   * NSSM once again calls TerminateProcess() correctly.

+ 7 - 0
README.txt

@@ -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
 timeouts if the application spawns multiple subprocesses.
 
+To skip applying the above stop methods to all processes in the application's
+process tree, applying them only to the original application process, set the
+HKLM\SYSTEM\CurrentControlSet\Services\<service>\Parameters\AppKillProcessTree
+registry value, which should be of type REG_DWORD, to 0.
+
 
 Console window
 --------------
@@ -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
 run under a local user account.
 Thanks to Sam Townsend for noticing a regression with TerminateProcess().
+Thanks to Barrett Lewis for suggesting the option to skip terminating the
+application's child processes.
 
 Licence
 -------

+ 6 - 0
gui.cpp

@@ -153,6 +153,9 @@ int nssm_gui(int resource, nssm_service_t *service) {
     if (! (service->stop_method & NSSM_STOP_METHOD_TERMINATE)) {
       SendDlgItemMessage(tablist[NSSM_TAB_SHUTDOWN], IDC_METHOD_TERMINATE, BM_SETCHECK, BST_UNCHECKED, 0);
     }
+    if (! service->kill_process_tree) {
+      SendDlgItemMessage(tablist[NSSM_TAB_SHUTDOWN], IDC_KILL_PROCESS_TREE, BM_SETCHECK, BST_UNCHECKED, 0);
+    }
 
     /* Restart tab. */
     SetDlgItemInt(tablist[NSSM_TAB_EXIT], IDC_THROTTLE, service->throttle_delay, 0);
@@ -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);
   check_number(tablist[NSSM_TAB_SHUTDOWN], IDC_KILL_WINDOW, &service->kill_window_delay);
   check_number(tablist[NSSM_TAB_SHUTDOWN], IDC_KILL_THREADS, &service->kill_threads_delay);
+  if (SendDlgItemMessage(tablist[NSSM_TAB_SHUTDOWN], IDC_KILL_PROCESS_TREE, BM_GETCHECK, 0, 0) & BST_CHECKED) service->kill_process_tree = 1;
+  else service->kill_process_tree = 0;
 
   /* Get exit action stuff. */
   check_number(tablist[NSSM_TAB_EXIT], IDC_THROTTLE, &service->throttle_delay);
@@ -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);
       SetDlgItemInt(tablist[NSSM_TAB_SHUTDOWN], IDC_KILL_THREADS, NSSM_KILL_THREADS_GRACE_PERIOD, 0);
       SendDlgItemMessage(tablist[NSSM_TAB_SHUTDOWN], IDC_METHOD_TERMINATE, BM_SETCHECK, BST_CHECKED, 0);
+      SendDlgItemMessage(tablist[NSSM_TAB_SHUTDOWN], IDC_KILL_PROCESS_TREE, BM_SETCHECK, BST_CHECKED, 1);
 
       /* Restart tab. */
       tab.pszText = message_string(NSSM_GUI_TAB_EXIT);

BIN
nssm.rc


+ 10 - 0
registry.cpp

@@ -79,6 +79,8 @@ int create_parameters(nssm_service_t *service, bool editing) {
   else if (editing) RegDeleteValue(key, NSSM_REG_KILL_WINDOW_GRACE_PERIOD);
   if (service->kill_threads_delay != NSSM_KILL_THREADS_GRACE_PERIOD) set_number(key, NSSM_REG_KILL_THREADS_GRACE_PERIOD, service->kill_threads_delay);
   else if (editing) RegDeleteValue(key, NSSM_REG_KILL_THREADS_GRACE_PERIOD);
+  if (! service->kill_process_tree) set_number(key, NSSM_REG_KILL_PROCESS_TREE, 0);
+  else if (editing) RegDeleteValue(key, NSSM_REG_KILL_PROCESS_TREE);
   if (service->stdin_path[0] || editing) {
     if (service->stdin_path[0]) set_expand_string(key, NSSM_REG_STDIN, service->stdin_path);
     else if (editing) RegDeleteValue(key, NSSM_REG_STDIN);
@@ -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);
   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);
 
+  /* Try to get process tree settings - may fail. */
+  unsigned long kill_process_tree;
+  if (get_number(key, NSSM_REG_KILL_PROCESS_TREE, &kill_process_tree, false) == 1) {
+    if (kill_process_tree) service->kill_process_tree = true;
+    else service->kill_process_tree = false;
+  }
+  else service->kill_process_tree = true;
+
   /* Try to get default exit action. */
   bool default_action;
   service->default_exit_action = NSSM_EXIT_RESTART;

+ 1 - 0
registry.h

@@ -16,6 +16,7 @@
 #define NSSM_REG_KILL_CONSOLE_GRACE_PERIOD _T("AppStopMethodConsole")
 #define NSSM_REG_KILL_WINDOW_GRACE_PERIOD _T("AppStopMethodWindow")
 #define NSSM_REG_KILL_THREADS_GRACE_PERIOD _T("AppStopMethodThreads")
+#define NSSM_REG_KILL_PROCESS_TREE _T("AppKillProcessTree")
 #define NSSM_REG_STDIN _T("AppStdin")
 #define NSSM_REG_STDOUT _T("AppStdout")
 #define NSSM_REG_STDERR _T("AppStderr")

+ 2 - 1
resource.h

@@ -64,6 +64,7 @@
 #define IDC_AFFINITY                    1044
 #define IDC_CONSOLE                     1045
 #define IDC_DEPENDENCIES                1046
+#define IDC_KILL_PROCESS_TREE           1047
 
 // Next default values for new objects
 // 
@@ -71,7 +72,7 @@
 #ifndef APSTUDIO_READONLY_SYMBOLS
 #define _APS_NEXT_RESOURCE_VALUE        115
 #define _APS_NEXT_COMMAND_VALUE         40001
-#define _APS_NEXT_CONTROL_VALUE         1047
+#define _APS_NEXT_CONTROL_VALUE         1048
 #define _APS_NEXT_SYMED_VALUE           101
 #endif
 #endif

+ 2 - 1
service.cpp

@@ -689,6 +689,7 @@ void set_nssm_service_defaults(nssm_service_t *service) {
   service->kill_console_delay = NSSM_KILL_CONSOLE_GRACE_PERIOD;
   service->kill_window_delay = NSSM_KILL_WINDOW_GRACE_PERIOD;
   service->kill_threads_delay = NSSM_KILL_THREADS_GRACE_PERIOD;
+  service->kill_process_tree = 1;
 }
 
 /* Allocate and zero memory for a service. */
@@ -1800,7 +1801,7 @@ void CALLBACK end_service(void *arg, unsigned char why) {
 
   /* Clean up. */
   if (exitcode == STILL_ACTIVE) exitcode = 0;
-  if (service->pid) kill_process_tree(service, service->pid, exitcode, service->pid);
+  if (service->pid && service->kill_process_tree) kill_process_tree(service, service->pid, exitcode, service->pid);
   service->pid = 0;
 
   /*

+ 1 - 0
service.h

@@ -84,6 +84,7 @@ typedef struct {
   unsigned long kill_console_delay;
   unsigned long kill_window_delay;
   unsigned long kill_threads_delay;
+  bool kill_process_tree;
   SC_HANDLE handle;
   SERVICE_STATUS status;
   SERVICE_STATUS_HANDLE status_handle;

+ 1 - 0
settings.cpp

@@ -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 },