mirror of
https://github.com/neovim/neovim.git
synced 2026-08-25 16:41:52 +00:00
fix(lifecycle): on Windows, CTRL_CLOSE kills Nvim mid-teardown
Problem:
`signal_ignore_deadly` doesn't work for Windows, where the console still
may terminate Nvim during teardown (after `signal_teardown`), while it
is already trying to exit. Besides interrupting any housekeeping we are
doing, it results in an unpredictable exit code (flaky tests).
[Process exited -1073741510] // 0xC000013A STATUS_CONTROL_C_EXIT
Solution:
Register our own CTRL_CLOSE_EVENT handler which "blocks" the signal.
Note: if exit takes longer than 5s, Windows will consider the process
"hung" and kill it anyway.
This commit is contained in:
@@ -66,14 +66,32 @@ void signal_init(void)
|
||||
signal_start();
|
||||
}
|
||||
|
||||
#ifdef MSWIN
|
||||
/// Swallows console control events during shutdown.
|
||||
static BOOL WINAPI signal_ctrl_handler(DWORD type)
|
||||
{
|
||||
switch (type) {
|
||||
case CTRL_CLOSE_EVENT:
|
||||
// Returning true is not enough; Windows terminates the process as soon as the handler returns.
|
||||
// So block instead, like libuv's own handler does, and let the exit finish.
|
||||
Sleep(INFINITE);
|
||||
return true;
|
||||
case CTRL_C_EVENT:
|
||||
case CTRL_BREAK_EVENT:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/// During shutdown, we don't want the default actions of these signals.
|
||||
///
|
||||
/// Note: Windows still has the race. libuv's console control handler dispatches CTRL_CLOSE_EVENT
|
||||
/// as SIGHUP, but only while a watcher is registered; signal_teardown() closed ours, so the
|
||||
/// console terminates Nvim with STATUS_CONTROL_C_EXIT (-1073741510).
|
||||
static void signal_ignore_deadly(void)
|
||||
{
|
||||
#ifndef MSWIN
|
||||
#ifdef MSWIN
|
||||
// Handlers run in reverse registration order, so this one runs before libuv's.
|
||||
SetConsoleCtrlHandler(signal_ctrl_handler, true);
|
||||
#else
|
||||
signal(SIGHUP, SIG_IGN);
|
||||
signal(SIGINT, SIG_IGN);
|
||||
signal(SIGTERM, SIG_IGN);
|
||||
|
||||
@@ -3669,10 +3669,7 @@ describe('TUI', function()
|
||||
retry(nil, 2000, function()
|
||||
eq(vim.NIL, api.nvim_get_proc(pid))
|
||||
end)
|
||||
-- On Windows the console terminates the child with STATUS_CONTROL_C_EXIT (-1073741510).
|
||||
screen:expect({
|
||||
any = is_os('win') and '%[Process exited %-?%d+%]' or '%[Process exited 1%]',
|
||||
})
|
||||
screen:expect({ any = '%[Process exited 1%]' })
|
||||
-- Closing stdin must skip the DA1 wait.
|
||||
t.assert_nolog('timed out waiting for DA1 response', testlog, 100)
|
||||
end)
|
||||
|
||||
Reference in New Issue
Block a user