Ensure logging threads exit.
authorIain Patterson <me@iain.cx>
Tue, 30 Aug 2016 07:37:00 +0000 (08:37 +0100)
committerIain Patterson <me@iain.cx>
Mon, 5 Sep 2016 07:52:23 +0000 (08:52 +0100)
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.

io.cpp
io.h
nssm.h
service.cpp

diff --git a/io.cpp b/io.cpp
index 0c904be..48611b0 100644 (file)
--- a/io.cpp
+++ b/io.cpp
@@ -428,6 +428,24 @@ void close_output_handles(STARTUPINFO *si) {
   if (si->hStdError) CloseHandle(si->hStdError);\r
 }\r
 \r
+void cleanup_loggers(nssm_service_t *service) {\r
+  unsigned long interval = NSSM_CLEANUP_LOGGERS_DEADLINE;\r
+  HANDLE thread_handle = INVALID_HANDLE_VALUE;\r
+\r
+  close_handle(&service->stdout_thread, &thread_handle);\r
+  /* Close write end of the data pipe so logging thread can finalise read. */\r
+  close_handle(&service->stdout_si);\r
+  /* Await logging thread then close read end. */\r
+  if (thread_handle != INVALID_HANDLE_VALUE) WaitForSingleObject(thread_handle, interval);\r
+  close_handle(&service->stdout_pipe);\r
+\r
+  thread_handle = INVALID_HANDLE_VALUE;\r
+  close_handle(&service->stderr_thread, &thread_handle);\r
+  close_handle(&service->stderr_si);\r
+  if (thread_handle != INVALID_HANDLE_VALUE) WaitForSingleObject(thread_handle, interval);\r
+  close_handle(&service->stderr_pipe);\r
+}\r
+\r
 /*\r
   Try multiple times to read from a file.\r
   Returns:  0 on success.\r
diff --git a/io.h b/io.h
index 31f1e0d..af7e662 100644 (file)
--- a/io.h
+++ b/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 *);\r
 int use_output_handles(nssm_service_t *, STARTUPINFO *);\r
 void close_output_handles(STARTUPINFO *);\r
+void cleanup_loggers(nssm_service_t *);\r
 unsigned long WINAPI log_and_rotate(void *);\r
 \r
 #endif\r
diff --git a/nssm.h b/nssm.h
index 214d1d8..e50f946 100644 (file)
--- a/nssm.h
+++ b/nssm.h
@@ -156,4 +156,7 @@ const TCHAR *nssm_exe();
 /* How many milliseconds to wait for outstanding hooks. */\r
 #define NSSM_HOOK_THREAD_DEADLINE 80000\r
 \r
+/* How many milliseconds to wait for closing logging thread. */\r
+#define NSSM_CLEANUP_LOGGERS_DEADLINE 1500\r
+\r
 #endif\r
index d66b916..937a2ec 100644 (file)
@@ -2060,6 +2060,9 @@ void CALLBACK end_service(void *arg, unsigned char why) {
   service->exit_count++;\r
   (void) nssm_hook(&hook_threads, service, NSSM_HOOK_EVENT_EXIT, NSSM_HOOK_ACTION_POST, NULL, NSSM_HOOK_DEADLINE, true);\r
 \r
+  /* Exit logging threads. */\r
+  cleanup_loggers(service);\r
+\r
   /*\r
     The why argument is true if our wait timed out or false otherwise.\r
     Our wait is infinite so why will never be true when called by the system.\r