mirror of
https://github.com/tangerineturtle1/NX2navi.git
synced 2026-11-15 19:19:58 -04:00
End the process on a second Ctrl+C after a save Commit in flight finishes, not through the default handler's ExitProcess.
win32.c con_ctrl returned FALSE for a second Ctrl+C, Ctrl+Break or close while the first one's end ran, so the next handler, the default one, ran ExitProcess at once: a save Commit in flight was cut (the next start rolls it back) and every library's detach ran. Only a game started from a console has the handler; the launcher starts it with no console. The second event now waits for a Commit under way through fs_save_crash_wait (2 s at most, no lock; weak in win32.c for builds without fs_host.c, as dispatch.c has it) and ends the process with plat_exit and STATUS_CONTROL_C_EXIT, the code the default handler gives. The force-quit stays; it takes up to 2 s longer when a Commit runs. Not reproduced before the change (a play-test item from a console: Ctrl+C twice). By review; fatal_exit_check, logq_check and save_share_check, which link win32.c beside a weak or a strong fs_save_crash_wait, and the compile checks pass. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1332,13 +1332,22 @@ static DWORD con_mode;
|
||||
static void (*con_close)(const char *what);
|
||||
static volatile LONG con_closing;
|
||||
|
||||
// fs_host.c: a save Commit under way finishes first, 2 s at most and without a lock; builds without it have no saves
|
||||
__attribute__((weak)) void fs_save_crash_wait(void) {}
|
||||
|
||||
// Runs on a thread the system starts for the event. A close returns only when on_close does, which it must not.
|
||||
static BOOL WINAPI con_ctrl(DWORD ev) {
|
||||
const char *what = ev == CTRL_CLOSE_EVENT ? "closed" : ev == CTRL_C_EVENT ? "Ctrl+C"
|
||||
: ev == CTRL_BREAK_EVENT ? "Ctrl+Break" : NULL;
|
||||
// log-off and shutdown reach a process with a window as WM_ENDSESSION (gfx_window_win.c), not here; a second event
|
||||
// while on_close runs takes the default path, which ends the process at once
|
||||
if (!what || !con_close || InterlockedExchange(&con_closing, 1)) return FALSE;
|
||||
// log-off and shutdown reach a process with a window as WM_ENDSESSION (gfx_window_win.c), not here
|
||||
if (!what || !con_close) return FALSE;
|
||||
if (InterlockedExchange(&con_closing, 1)) {
|
||||
// A second event while on_close runs: the player wants out now. Left to the default handler, its ExitProcess
|
||||
// cut a save Commit in flight and ran every library's detach; the Commit finishes first, and the process ends
|
||||
// with the code the default handler gives (STATUS_CONTROL_C_EXIT).
|
||||
fs_save_crash_wait();
|
||||
plat_exit((int)0xC000013Au);
|
||||
}
|
||||
con_close(what);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user