diff --git a/common/logger.h b/common/logger.h index 950efb5..d2192f3 100644 --- a/common/logger.h +++ b/common/logger.h @@ -228,16 +228,19 @@ private: } // 后台线程处理日志 + // 退出语义:stop() 设 running=false 后,本线程必须把队列里**已入队**的日志 + // 全部刷盘再退出。否则进程死亡前最后几条 Mprintf(包括退出原因)会丢失。 void processLogs() { threadRun = true; - while (running) { + while (true) { std::unique_lock lock(queueMutex); cv.wait(lock, [this]() { return !running || !logQueue.empty(); }); - while (running && !logQueue.empty()) { + // drain:不带 running 判断,确保 stop() 时残留条目也写完 + while (!logQueue.empty()) { std::string logEntry = logQueue.front(); logQueue.pop(); lock.unlock(); @@ -247,7 +250,9 @@ private: lock.lock(); } - lock.unlock(); + + // 队列已空再决定要不要退出 + if (!running) break; } threadRun = false; } diff --git a/linux/main.cpp b/linux/main.cpp index 1b0c87e..84ca1ff 100644 --- a/linux/main.cpp +++ b/linux/main.cpp @@ -786,8 +786,12 @@ static void daemonize() } // 信号处理:收到 SIGTERM/SIGINT 时优雅退出 +// 注意:handler 内不能调 Mprintf(Logger 用 mutex/string/condvar,非 async-signal-safe), +// 只在这里记 sig_atomic_t 标志位,main 退出循环后再补一行日志。 +static volatile sig_atomic_t g_lastSignal = 0; static void signalHandler(int sig) { + g_lastSignal = sig; g_bExit = S_CLIENT_EXIT; } @@ -1060,6 +1064,14 @@ int main(int argc, char* argv[]) } } + // 退出原因留痕:signal handler 不能直接打日志,在这里补一行。 + if (g_lastSignal != 0) { + Mprintf(">>> Exit by signal %d (g_bExit=%d)\n", + (int)g_lastSignal, (int)g_bExit); + } else { + Mprintf(">>> Exit normally (g_bExit=%d)\n", (int)g_bExit); + } + Logger::getInstance().stop(); removePidFile(); return 0; diff --git a/macos/main.mm b/macos/main.mm index f3e2f31..129e2c5 100644 --- a/macos/main.mm +++ b/macos/main.mm @@ -604,9 +604,13 @@ static void fillLoginInfo(LOGIN_INFOR& info) // ============== Signal Handling ============== +// 注意:signal handler 内不能调 NSLog/Mprintf(NSLog 走 Foundation 锁, +// Mprintf 走 Logger mutex/condvar),都不是 async-signal-safe。只在这里 +// 记 sig_atomic_t 标志位,main 退出循环后再补一行日志。 +static volatile sig_atomic_t g_lastSignal = 0; static void signalHandler(int sig) { - NSLog(@"Received signal %d, shutting down...", sig); + g_lastSignal = sig; g_running = false; g_bExit = S_CLIENT_EXIT; // 通知所有工作线程退出 } @@ -934,6 +938,14 @@ int main(int argc, const char* argv[]) } } + // 退出原因留痕:signal handler 不能直接打日志,在这里补一行。 + if (g_lastSignal != 0) { + Mprintf(">>> Exit by signal %d (g_bExit=%d)\n", + (int)g_lastSignal, (int)g_bExit); + } else { + Mprintf(">>> Exit normally (g_bExit=%d)\n", (int)g_bExit); + } + NSLog(@"Shutting down..."); // Release power assertions @@ -944,6 +956,10 @@ int main(int argc, const char* argv[]) // Display assertion is managed by ScreenHandler (released in stop()) // powerActivity is automatically released when exiting @autoreleasepool (void)powerActivity; // Suppress unused variable warning + + // 显式停止日志,确保上面 Mprintf 的退出原因落盘。 + // 不依赖 ~Logger() 的静态析构次序,避免后续新增日志相关静态对象时踩坑。 + Logger::getInstance().stop(); } return 0;