mirror of
https://github.com/neovim/neovim.git
synced 2025-09-29 22:48:34 +00:00
loop_close: Avoid infinite loop, and log it.
Avoids a hang, and also helps diagnose issues like: https://github.com/neovim/neovim/pull/6594#issuecomment-298321826
This commit is contained in:
@@ -8,6 +8,7 @@
|
||||
|
||||
#include "nvim/event/loop.h"
|
||||
#include "nvim/event/process.h"
|
||||
#include "nvim/log.h"
|
||||
|
||||
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
||||
# include "event/loop.c.generated.h"
|
||||
@@ -78,20 +79,34 @@ void loop_on_put(MultiQueue *queue, void *data)
|
||||
uv_stop(&loop->uv);
|
||||
}
|
||||
|
||||
void loop_close(Loop *loop, bool wait)
|
||||
/// @returns false if the loop could not be closed gracefully
|
||||
bool loop_close(Loop *loop, bool wait)
|
||||
{
|
||||
bool rv = true;
|
||||
uv_mutex_destroy(&loop->mutex);
|
||||
uv_close((uv_handle_t *)&loop->children_watcher, NULL);
|
||||
uv_close((uv_handle_t *)&loop->children_kill_timer, NULL);
|
||||
uv_close((uv_handle_t *)&loop->poll_timer, NULL);
|
||||
uv_close((uv_handle_t *)&loop->async, NULL);
|
||||
do {
|
||||
uint64_t start = wait ? os_hrtime() : 0;
|
||||
while (true) {
|
||||
uv_run(&loop->uv, wait ? UV_RUN_DEFAULT : UV_RUN_NOWAIT);
|
||||
} while (uv_loop_close(&loop->uv) && wait);
|
||||
if (!uv_loop_close(&loop->uv) || !wait) {
|
||||
break;
|
||||
}
|
||||
if (os_hrtime() - start >= 2 * 1000000000) {
|
||||
// Some libuv resource was not correctly deref'd. Log and bail.
|
||||
rv = false;
|
||||
ELOG("uv_loop_close() hang?");
|
||||
log_uv_handles(&loop->uv);
|
||||
break;
|
||||
}
|
||||
}
|
||||
multiqueue_free(loop->fast_events);
|
||||
multiqueue_free(loop->thread_events);
|
||||
multiqueue_free(loop->events);
|
||||
kl_destroy(WatcherPtr, loop->children);
|
||||
return rv;
|
||||
}
|
||||
|
||||
void loop_purge(Loop *loop)
|
||||
|
@@ -153,10 +153,11 @@ void event_init(void)
|
||||
terminal_init();
|
||||
}
|
||||
|
||||
void event_teardown(void)
|
||||
/// @returns false if main_loop could not be closed gracefully
|
||||
bool event_teardown(void)
|
||||
{
|
||||
if (!main_loop.events) {
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
multiqueue_process_events(main_loop.events);
|
||||
@@ -168,7 +169,7 @@ void event_teardown(void)
|
||||
signal_teardown();
|
||||
terminal_teardown();
|
||||
|
||||
loop_close(&main_loop, true);
|
||||
return loop_close(&main_loop, true);
|
||||
}
|
||||
|
||||
/// Performs early initialization.
|
||||
|
@@ -141,7 +141,9 @@ void mch_exit(int r) FUNC_ATTR_NORETURN
|
||||
ui_flush();
|
||||
ml_close_all(true); // remove all memfiles
|
||||
|
||||
event_teardown();
|
||||
if (!event_teardown() && r == 0) {
|
||||
r = 1; // Exit with error if main_loop did not teardown gracefully.
|
||||
}
|
||||
stream_set_blocking(input_global_fd(), true); // normalize stream (#2598)
|
||||
|
||||
#ifdef EXITFREE
|
||||
|
Reference in New Issue
Block a user