Browse Source

Ensure logging threads exit.

We need to close all handles to ensure that all logging threads are
joined.

Care must be taken to close the writing end of the logging pipe first so
that the logging thread can issue a final ReadFile() call.  Before the
thread exits it should close the reading end, however as a safety
measure we WaitForSingleObject() then close the reading end from the
main rotation thread.
Iain Patterson 5 years ago
parent
commit
ee9a86c840
4 changed files with 25 additions and 0 deletions
  1. 18 0
      io.cpp
  2. 1 0
      io.h
  3. 3 0
      nssm.h
  4. 3 0
      service.cpp

+ 18 - 0
io.cpp

@@ -428,6 +428,24 @@ void close_output_handles(STARTUPINFO *si) {
   if (si->hStdError) CloseHandle(si->hStdError);
 }
 
+void cleanup_loggers(nssm_service_t *service) {
+  unsigned long interval = NSSM_CLEANUP_LOGGERS_DEADLINE;
+  HANDLE thread_handle = INVALID_HANDLE_VALUE;
+
+  close_handle(&service->stdout_thread, &thread_handle);
+  /* Close write end of the data pipe so logging thread can finalise read. */
+  close_handle(&service->stdout_si);
+  /* Await logging thread then close read end. */
+  if (thread_handle != INVALID_HANDLE_VALUE) WaitForSingleObject(thread_handle, interval);
+  close_handle(&service->stdout_pipe);
+
+  thread_handle = INVALID_HANDLE_VALUE;
+  close_handle(&service->stderr_thread, &thread_handle);
+  close_handle(&service->stderr_si);
+  if (thread_handle != INVALID_HANDLE_VALUE) WaitForSingleObject(thread_handle, interval);
+  close_handle(&service->stderr_pipe);
+}
+
 /*
   Try multiple times to read from a file.
   Returns:  0 on success.

+ 1 - 0
io.h

@@ -38,6 +38,7 @@ void rotate_file(TCHAR *, TCHAR *, unsigned long, unsigned long, unsigned long,
 int get_output_handles(nssm_service_t *, STARTUPINFO *);
 int use_output_handles(nssm_service_t *, STARTUPINFO *);
 void close_output_handles(STARTUPINFO *);
+void cleanup_loggers(nssm_service_t *);
 unsigned long WINAPI log_and_rotate(void *);
 
 #endif

+ 3 - 0
nssm.h

@@ -156,4 +156,7 @@ const TCHAR *nssm_exe();
 /* How many milliseconds to wait for outstanding hooks. */
 #define NSSM_HOOK_THREAD_DEADLINE 80000
 
+/* How many milliseconds to wait for closing logging thread. */
+#define NSSM_CLEANUP_LOGGERS_DEADLINE 1500
+
 #endif

+ 3 - 0
service.cpp

@@ -2060,6 +2060,9 @@ void CALLBACK end_service(void *arg, unsigned char why) {
   service->exit_count++;
   (void) nssm_hook(&hook_threads, service, NSSM_HOOK_EVENT_EXIT, NSSM_HOOK_ACTION_POST, NULL, NSSM_HOOK_DEADLINE, true);
 
+  /* Exit logging threads. */
+  cleanup_loggers(service);
+
   /*
     The why argument is true if our wait timed out or false otherwise.
     Our wait is infinite so why will never be true when called by the system.