refactor(exit): pass error message to preserve_exit() (#22097)

Problem:
1. Some calls to preserve_exit() don't put a message in IObuff, so the
   IObuff printed by preserve_exit() contains unrelated information.
2. If a TUI client runs out of memory or receives a deadly signal, the
   error message is shown on alternate screen and cannot be easily seen
   because the TUI exits alternate screen soon afterwards.

Solution:
Pass error message to preserve_exit() and exit alternate screen before
printing it.

Note that this doesn't fix the problem that server error messages cannot
be easily seen on exit. This is tracked in #21608 and #21843.
This commit is contained in:
zeertzjq 2023-02-04 20:14:31 +08:00 committed by GitHub
parent 90333b24c3
commit 69bb145cea
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 21 additions and 30 deletions

View File

@ -155,7 +155,7 @@ static void fread_idle_cb(uv_idle_t *handle)
uintmax_t fpos_intmax = stream->fpos; uintmax_t fpos_intmax = stream->fpos;
if (fpos_intmax > INT64_MAX) { if (fpos_intmax > INT64_MAX) {
ELOG("stream offset overflow"); ELOG("stream offset overflow");
preserve_exit(); preserve_exit("stream offset overflow");
} }
// Synchronous read // Synchronous read

View File

@ -211,9 +211,7 @@ static int nlua_luv_cfpcall(lua_State *lstate, int nargs, int nresult, int flags
if (status) { if (status) {
if (status == LUA_ERRMEM && !(flags & LUVF_CALLBACK_NOEXIT)) { if (status == LUA_ERRMEM && !(flags & LUVF_CALLBACK_NOEXIT)) {
// consider out of memory errors unrecoverable, just like xmalloc() // consider out of memory errors unrecoverable, just like xmalloc()
os_errmsg(e_outofmem); preserve_exit(e_outofmem);
os_errmsg("\n");
preserve_exit();
} }
const char *error = lua_tostring(lstate, -1); const char *error = lua_tostring(lstate, -1);

View File

@ -790,10 +790,10 @@ void getout(int exitval)
os_exit(exitval); os_exit(exitval);
} }
/// Preserve files, print contents of `IObuff`, and exit 1. /// Preserve files, print contents of `errmsg`, and exit 1.
/// ///
/// May be called from deadly_signal(). /// May be called from deadly_signal().
void preserve_exit(void) void preserve_exit(const char *errmsg)
FUNC_ATTR_NORETURN FUNC_ATTR_NORETURN
{ {
// 'true' when we are sure to exit, e.g., after a deadly signal // 'true' when we are sure to exit, e.g., after a deadly signal
@ -812,12 +812,15 @@ void preserve_exit(void)
// Ignore SIGHUP while we are already exiting. #9274 // Ignore SIGHUP while we are already exiting. #9274
signal_reject_deadly(); signal_reject_deadly();
if (ui_client_channel_id) {
// For TUI: exit alternate screen so that the error messages can be seen.
ui_client_stop();
}
os_errmsg(errmsg);
os_errmsg("\n");
if (ui_client_channel_id) { if (ui_client_channel_id) {
os_exit(1); os_exit(1);
} }
os_errmsg(IObuff);
os_errmsg("\n");
ui_flush(); ui_flush();
ml_close_notmod(); // close all not-modified buffers ml_close_notmod(); // close all not-modified buffers

View File

@ -121,9 +121,7 @@ void *xmalloc(size_t size)
{ {
void *ret = try_malloc(size); void *ret = try_malloc(size);
if (!ret) { if (!ret) {
os_errmsg(e_outofmem); preserve_exit(e_outofmem);
os_errmsg("\n");
preserve_exit();
} }
return ret; return ret;
} }
@ -152,9 +150,7 @@ void *xcalloc(size_t count, size_t size)
try_to_free_memory(); try_to_free_memory();
ret = calloc(allocated_count, allocated_size); ret = calloc(allocated_count, allocated_size);
if (!ret) { if (!ret) {
os_errmsg(e_outofmem); preserve_exit(e_outofmem);
os_errmsg("\n");
preserve_exit();
} }
} }
return ret; return ret;
@ -174,9 +170,7 @@ void *xrealloc(void *ptr, size_t size)
try_to_free_memory(); try_to_free_memory();
ret = realloc(ptr, allocated_size); ret = realloc(ptr, allocated_size);
if (!ret) { if (!ret) {
os_errmsg(e_outofmem); preserve_exit(e_outofmem);
os_errmsg("\n");
preserve_exit();
} }
} }
return ret; return ret;
@ -194,8 +188,7 @@ void *xmallocz(size_t size)
{ {
size_t total_size = size + 1; size_t total_size = size + 1;
if (total_size < size) { if (total_size < size) {
os_errmsg(_("Vim: Data too large to fit into virtual memory space\n")); preserve_exit(_("Vim: Data too large to fit into virtual memory space\n"));
preserve_exit();
} }
void *ret = xmalloc(total_size); void *ret = xmalloc(total_size);

View File

@ -550,8 +550,7 @@ static void read_error_exit(void)
if (silent_mode) { // Normal way to exit for "nvim -es". if (silent_mode) { // Normal way to exit for "nvim -es".
getout(0); getout(0);
} }
STRCPY(IObuff, _("Vim: Error reading input, exiting...\n")); preserve_exit(_("Vim: Error reading input, exiting...\n"));
preserve_exit();
} }
static bool pending_events(MultiQueue *events) static bool pending_events(MultiQueue *events)

View File

@ -172,11 +172,10 @@ static void deadly_signal(int signum)
ILOG("got signal %d (%s)", signum, signal_name(signum)); ILOG("got signal %d (%s)", signum, signal_name(signum));
snprintf(IObuff, sizeof(IObuff), "Vim: Caught deadly signal '%s'\r\n", snprintf(IObuff, IOSIZE, "Vim: Caught deadly signal '%s'\r\n", signal_name(signum));
signal_name(signum));
// Preserve files and exit. // Preserve files and exit.
preserve_exit(); preserve_exit(IObuff);
} }
static void on_signal(SignalWatcher *handle, int signum, void *data) static void on_signal(SignalWatcher *handle, int signum, void *data)

View File

@ -458,9 +458,6 @@ static void tui_terminal_stop(TUIData *tui)
void tui_stop(TUIData *tui) void tui_stop(TUIData *tui)
{ {
if (tui->stopped) {
return;
}
tui_terminal_stop(tui); tui_terminal_stop(tui);
stream_set_blocking(tui->input.in_fd, true); // normalize stream (#2598) stream_set_blocking(tui->input.in_fd, true); // normalize stream (#2598)
tinput_destroy(&tui->input); tinput_destroy(&tui->input);
@ -470,7 +467,7 @@ void tui_stop(TUIData *tui)
} }
/// Returns true if UI `ui` is stopped. /// Returns true if UI `ui` is stopped.
static bool tui_is_stopped(TUIData *tui) bool tui_is_stopped(TUIData *tui)
{ {
return tui->stopped; return tui->stopped;
} }

View File

@ -122,7 +122,9 @@ void ui_client_run(bool remote_ui)
void ui_client_stop(void) void ui_client_stop(void)
{ {
tui_stop(tui); if (!tui_is_stopped(tui)) {
tui_stop(tui);
}
} }
void ui_client_set_size(int width, int height) void ui_client_set_size(int width, int height)