Skip to content

Commit d111033

Browse files
authored
fix: 修复退出程序后异常重启 (#640)
* fix(logging): 增强异步sinks的退出顺序 * fix(system_tray): 增强安全退出机制 * fix(main): 确保正确退出 * fix(main): 确保正确退出
1 parent 5a6950f commit d111033

3 files changed

Lines changed: 60 additions & 8 deletions

File tree

src/logging.cpp

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,16 +56,29 @@ namespace logging {
5656
void
5757
deinit() {
5858
log_flush();
59+
60+
// Order matters for async sinks:
61+
// 1) remove_sink: detach the sink from the boost::log core so no new records are delivered
62+
// 2) stop: signal the worker thread to exit and wait for it to finish
63+
// 3) flush: drain any remaining records
64+
// 4) reset: drop our shared_ptr; sink destructor runs once the last ref is gone
65+
auto core = bl::core::get();
66+
5967
if (console_sink) {
60-
bl::core::get()->remove_sink(console_sink);
68+
core->remove_sink(console_sink);
69+
console_sink->stop();
70+
console_sink->flush();
6171
console_sink.reset();
6272
}
6373
if (file_sink_ptr) {
64-
bl::core::get()->remove_sink(file_sink_ptr);
74+
core->remove_sink(file_sink_ptr);
75+
file_sink_ptr->flush();
6576
file_sink_ptr.reset();
6677
}
6778
if (file_ostream_sink) {
68-
bl::core::get()->remove_sink(file_ostream_sink);
79+
core->remove_sink(file_ostream_sink);
80+
file_ostream_sink->stop();
81+
file_ostream_sink->flush();
6982
file_ostream_sink.reset();
7083
}
7184
}

src/main.cpp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
* @brief Definitions for the main entry point for Sunshine.
44
*/
55
// standard includes
6+
#include <atomic>
67
#include <codecvt>
78
#include <csignal>
89
#include <fstream>
@@ -32,6 +33,19 @@ extern "C" {
3233
#include "rswrapper.h"
3334
}
3435

36+
#ifdef _WIN32
37+
#ifndef WIN32_LEAN_AND_MEAN
38+
#define WIN32_LEAN_AND_MEAN
39+
#endif
40+
#include <windows.h>
41+
42+
namespace {
43+
// Captures the value main() ends up returning so the atexit terminator can use it.
44+
// Defaults to 0 (success) for the common case where main returns lifetime::desired_exit_code.
45+
std::atomic<int> g_final_exit_code { 0 };
46+
}
47+
#endif
48+
3549
using namespace std::literals;
3650

3751
std::map<int, std::function<void()>> signal_handlers;
@@ -123,6 +137,15 @@ main(int argc, char *argv[]) {
123137
task_pool_util::TaskPool::task_id_t force_shutdown = nullptr;
124138

125139
#ifdef _WIN32
140+
// Note: this only fires on a normal `return` from main. If the program
141+
// crashes mid-run (uncaught exception, AV, abort/terminate), atexit is
142+
// not invoked, so the service supervisor still observes a non-zero exit
143+
// code and can restart Sunshine as usual.
144+
std::atexit([]() {
145+
TerminateProcess(GetCurrentProcess(),
146+
static_cast<UINT>(g_final_exit_code.load(std::memory_order_acquire)));
147+
});
148+
126149
// Avoid searching the PATH in case a user has configured their system insecurely
127150
// by placing a user-writable directory in the system-wide PATH variable.
128151
SetDefaultDllDirectories(LOAD_LIBRARY_SEARCH_APPLICATION_DIR | LOAD_LIBRARY_SEARCH_SYSTEM32);
@@ -451,5 +474,12 @@ main(int argc, char *argv[]) {
451474
}
452475
#endif
453476

477+
#ifdef _WIN32
478+
// Hand the chosen exit code over to the atexit terminator so it can pass it
479+
// straight to TerminateProcess. Without this the terminator would always
480+
// exit with 0 even when lifetime::desired_exit_code was set non-zero by a
481+
// failure path that still chose to return cleanly from main.
482+
g_final_exit_code.store(lifetime::desired_exit_code, std::memory_order_release);
483+
#endif
454484
return lifetime::desired_exit_code;
455485
}

src/system_tray.cpp

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1234,6 +1234,15 @@ namespace system_tray {
12341234

12351235
tray_initialized = false;
12361236
tray_exit();
1237+
1238+
if (tray_thread.joinable()) {
1239+
try {
1240+
tray_thread.join();
1241+
}
1242+
catch (const std::system_error &e) {
1243+
BOOST_LOG(warning) << "Failed to join tray thread: " << e.what();
1244+
}
1245+
}
12371246
return 0;
12381247
}
12391248

@@ -1395,12 +1404,12 @@ namespace system_tray {
13951404
// Reset the end_tray flag for new tray instance
13961405
end_tray_called = false;
13971406

1398-
try {
1399-
auto tray_thread = std::thread(tray_thread_worker);
1407+
if (tray_thread.joinable()) {
1408+
tray_thread.join();
1409+
}
14001410

1401-
// The tray thread doesn't require strong lifetime management.
1402-
// It will exit asynchronously when tray_exit() is called.
1403-
tray_thread.detach();
1411+
try {
1412+
tray_thread = std::thread(tray_thread_worker);
14041413

14051414
BOOST_LOG(info) << "System tray thread initialized successfully"sv;
14061415
return 0;

0 commit comments

Comments
 (0)