mirror of
https://github.com/neovim/neovim.git
synced 2025-11-18 08:11:28 +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/loop.h"
|
||||||
#include "nvim/event/process.h"
|
#include "nvim/event/process.h"
|
||||||
|
#include "nvim/log.h"
|
||||||
|
|
||||||
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
||||||
# include "event/loop.c.generated.h"
|
# include "event/loop.c.generated.h"
|
||||||
@@ -78,20 +79,34 @@ void loop_on_put(MultiQueue *queue, void *data)
|
|||||||
uv_stop(&loop->uv);
|
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_mutex_destroy(&loop->mutex);
|
||||||
uv_close((uv_handle_t *)&loop->children_watcher, NULL);
|
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->children_kill_timer, NULL);
|
||||||
uv_close((uv_handle_t *)&loop->poll_timer, NULL);
|
uv_close((uv_handle_t *)&loop->poll_timer, NULL);
|
||||||
uv_close((uv_handle_t *)&loop->async, 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);
|
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->fast_events);
|
||||||
multiqueue_free(loop->thread_events);
|
multiqueue_free(loop->thread_events);
|
||||||
multiqueue_free(loop->events);
|
multiqueue_free(loop->events);
|
||||||
kl_destroy(WatcherPtr, loop->children);
|
kl_destroy(WatcherPtr, loop->children);
|
||||||
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop_purge(Loop *loop)
|
void loop_purge(Loop *loop)
|
||||||
|
|||||||
@@ -153,10 +153,11 @@ void event_init(void)
|
|||||||
terminal_init();
|
terminal_init();
|
||||||
}
|
}
|
||||||
|
|
||||||
void event_teardown(void)
|
/// @returns false if main_loop could not be closed gracefully
|
||||||
|
bool event_teardown(void)
|
||||||
{
|
{
|
||||||
if (!main_loop.events) {
|
if (!main_loop.events) {
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
multiqueue_process_events(main_loop.events);
|
multiqueue_process_events(main_loop.events);
|
||||||
@@ -168,7 +169,7 @@ void event_teardown(void)
|
|||||||
signal_teardown();
|
signal_teardown();
|
||||||
terminal_teardown();
|
terminal_teardown();
|
||||||
|
|
||||||
loop_close(&main_loop, true);
|
return loop_close(&main_loop, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Performs early initialization.
|
/// Performs early initialization.
|
||||||
|
|||||||
@@ -141,7 +141,9 @@ void mch_exit(int r) FUNC_ATTR_NORETURN
|
|||||||
ui_flush();
|
ui_flush();
|
||||||
ml_close_all(true); // remove all memfiles
|
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)
|
stream_set_blocking(input_global_fd(), true); // normalize stream (#2598)
|
||||||
|
|
||||||
#ifdef EXITFREE
|
#ifdef EXITFREE
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
Tests are run by `/cmake/RunTests.cmake` file, using busted.
|
Tests are run by `/cmake/RunTests.cmake` file, using busted.
|
||||||
|
|
||||||
|
For some failures, `.nvimlog` (or `$NVIM_LOG_FILE`) may provide insight.
|
||||||
|
|
||||||
## Directory structure
|
## Directory structure
|
||||||
|
|
||||||
Directories with tests: `/test/benchmark` for benchmarks, `/test/functional` for
|
Directories with tests: `/test/benchmark` for benchmarks, `/test/functional` for
|
||||||
|
|||||||
Reference in New Issue
Block a user