From ee9a86c8408feaf173733aea12a80211e5d74483 Mon Sep 17 00:00:00 2001 From: Iain Patterson Date: Tue, 30 Aug 2016 08:37:00 +0100 Subject: [PATCH] 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. --- io.cpp | 18 ++++++++++++++++++ io.h | 1 + nssm.h | 3 +++ service.cpp | 3 +++ 4 files changed, 25 insertions(+) diff --git a/io.cpp b/io.cpp index 0c904be..48611b0 100644 --- a/io.cpp +++ b/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. diff --git a/io.h b/io.h index 31f1e0d..af7e662 100644 --- 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 *); 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 diff --git a/nssm.h b/nssm.h index 214d1d8..e50f946 100644 --- a/nssm.h +++ b/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 diff --git a/service.cpp b/service.cpp index d66b916..937a2ec 100644 --- a/service.cpp +++ b/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. -- 2.7.4