mirror of
https://github.com/neovim/neovim.git
synced 2026-03-31 21:02:11 +00:00
fix(tui): call tcdrain() on stdout and stderr on exit (#38154)
Problem: On FreeBSD, output written to TTY may be lost on exit. Example test failure: FAILED test/functional/terminal/tui_spec.lua @ 2521: TUI no assert failure on deadly signal #21896 test/functional/terminal/tui_spec.lua:2523: Row 1 did not match. Expected: |*Nvim: Caught deadly signal 'SIGTERM' | |* | |*[Process exited 1]^ | |* | |* | | | |{5:-- TERMINAL --} | Actual: |* | |*[Process exited 1]{100:^ }| |*{100:~ }| |*{100:~ }| |*{3:[No Name] }| | | |{5:-- TERMINAL --} | To print the expect() call that would assert the current screen state, use screen:snapshot_util(). In case of non-deterministic failures, use screen:redraw_debug() to show all intermediate screen states. Snapshot: screen:expect([[ | [Process exited 1]{100:^ }| {100:~ }|*2 {3:[No Name] }| | {5:-- TERMINAL --} | ]]) stack traceback: test/functional/ui/screen.lua:909: in function '_wait' test/functional/ui/screen.lua:537: in function 'expect' test/functional/terminal/tui_spec.lua:2523: in function <test/functional/terminal/tui_spec.lua:2521> Solution: Call tcdrain() on stdout and stderr on exit. This problem is only observed on FreeBSD, but it probably doesn't hurt to do this on all platforms with termios.h. In fact using tcdrain() on PTY slave is no-op on Linux according to Linux kernel source code.
This commit is contained in:
@@ -717,7 +717,19 @@ void os_exit(int r)
|
||||
if (!event_teardown() && r == 0) {
|
||||
r = 1; // Exit with error if main_loop did not teardown gracefully.
|
||||
}
|
||||
if (!ui_client_channel_id) {
|
||||
if (ui_client_channel_id) {
|
||||
#ifdef HAVE_TERMIOS_H
|
||||
// Sometimes the final output to TTY can be lost (at least on FreeBSD).
|
||||
// Call tcdrain() to ensure all output has been transmitted to host terminal.
|
||||
// Do this after event_teardown() as libuv events may write to stderr.
|
||||
if (stdout_isatty) {
|
||||
tcdrain(STDOUT_FILENO);
|
||||
}
|
||||
if (stderr_isatty) {
|
||||
tcdrain(STDERR_FILENO);
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
ml_close_all(true); // remove all memfiles
|
||||
}
|
||||
if (used_stdin) {
|
||||
@@ -901,7 +913,7 @@ void preserve_exit(const char *errmsg)
|
||||
ui_client_stop();
|
||||
}
|
||||
if (errmsg != NULL && errmsg[0] != NUL) {
|
||||
size_t has_eol = '\n' == errmsg[strlen(errmsg) - 1];
|
||||
bool has_eol = '\n' == errmsg[strlen(errmsg) - 1];
|
||||
fprintf(stderr, has_eol ? "%s" : "%s\n", errmsg);
|
||||
}
|
||||
if (ui_client_channel_id) {
|
||||
|
||||
@@ -1369,16 +1369,12 @@ describe('jobs', function()
|
||||
]])
|
||||
|
||||
feed(':q<CR>')
|
||||
if is_os('freebsd') then
|
||||
screen:expect { any = vim.pesc('[Process exited 0]') }
|
||||
else
|
||||
screen:expect([[
|
||||
|
|
||||
[Process exited 0]^ |
|
||||
|*4
|
||||
{5:-- TERMINAL --} |
|
||||
]])
|
||||
end
|
||||
screen:expect([[
|
||||
|
|
||||
[Process exited 0]^ |
|
||||
|*4
|
||||
{5:-- TERMINAL --} |
|
||||
]])
|
||||
end)
|
||||
|
||||
it('uses real pipes for stdin/stdout #35984', function()
|
||||
|
||||
Reference in New Issue
Block a user