|
3 | 3 | * @brief Definitions for the main entry point for Sunshine. |
4 | 4 | */ |
5 | 5 | // standard includes |
| 6 | +#include <atomic> |
6 | 7 | #include <codecvt> |
7 | 8 | #include <csignal> |
8 | 9 | #include <fstream> |
@@ -32,6 +33,19 @@ extern "C" { |
32 | 33 | #include "rswrapper.h" |
33 | 34 | } |
34 | 35 |
|
| 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 | + |
35 | 49 | using namespace std::literals; |
36 | 50 |
|
37 | 51 | std::map<int, std::function<void()>> signal_handlers; |
@@ -123,6 +137,15 @@ main(int argc, char *argv[]) { |
123 | 137 | task_pool_util::TaskPool::task_id_t force_shutdown = nullptr; |
124 | 138 |
|
125 | 139 | #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 | + |
126 | 149 | // Avoid searching the PATH in case a user has configured their system insecurely |
127 | 150 | // by placing a user-writable directory in the system-wide PATH variable. |
128 | 151 | SetDefaultDllDirectories(LOAD_LIBRARY_SEARCH_APPLICATION_DIR | LOAD_LIBRARY_SEARCH_SYSTEM32); |
@@ -451,5 +474,12 @@ main(int argc, char *argv[]) { |
451 | 474 | } |
452 | 475 | #endif |
453 | 476 |
|
| 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 |
454 | 484 | return lifetime::desired_exit_code; |
455 | 485 | } |
0 commit comments