From 939a05633f99eeba8f4fb5dfff0e7bab940f361b Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Sun, 13 Feb 2022 00:12:11 -0500 Subject: [PATCH] loop: add pending work to loop-alive check (#3466) Pending work may be either (on any platform) pending_queue callbacks or (on unix) watcher_queue handles to add to the io poll object. Previously, we might have gotten somewhat stuck if the user caused an event to be added to one of these in the idle or prepare callbacks, or was embedding libuv. Refs: https://github.com/libuv/libuv/pull/3234 Refs: https://github.com/libuv/libuv/issues/3101 Refs: https://github.com/libuv/libuv/pull/3308 --- src/unix/core.c | 43 ++++++++++++++++++------------------- src/win/core.c | 49 +++++++++++++++++++------------------------ test/test-loop-time.c | 26 ++++++++++++++--------- 3 files changed, 59 insertions(+), 59 deletions(-) diff --git a/src/unix/core.c b/src/unix/core.c index 3dd3fd90a..e14c327ea 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -334,35 +334,36 @@ int uv_backend_fd(const uv_loop_t* loop) { } -int uv_backend_timeout(const uv_loop_t* loop) { - if (loop->stop_flag != 0) - return 0; - - if (!uv__has_active_handles(loop) && !uv__has_active_reqs(loop)) - return 0; - - if (!QUEUE_EMPTY(&loop->idle_handles)) - return 0; - - if (!QUEUE_EMPTY(&loop->pending_queue)) - return 0; - - if (loop->closing_handles) - return 0; - - return uv__next_timeout(loop); -} - - static int uv__loop_alive(const uv_loop_t* loop) { return uv__has_active_handles(loop) || uv__has_active_reqs(loop) || + !QUEUE_EMPTY(&loop->pending_queue) || loop->closing_handles != NULL; } +static int uv__backend_timeout(const uv_loop_t* loop) { + if (loop->stop_flag == 0 && + /* uv__loop_alive(loop) && */ + (uv__has_active_handles(loop) || uv__has_active_reqs(loop)) && + QUEUE_EMPTY(&loop->pending_queue) && + QUEUE_EMPTY(&loop->idle_handles) && + loop->closing_handles == NULL) + return uv__next_timeout(loop); + return 0; +} + + +int uv_backend_timeout(const uv_loop_t* loop) { + if (QUEUE_EMPTY(&loop->watcher_queue)) + return uv__backend_timeout(loop); + /* Need to call uv_run to update the backend fd state. */ + return 0; +} + + int uv_loop_alive(const uv_loop_t* loop) { - return uv__loop_alive(loop); + return uv__loop_alive(loop); } diff --git a/src/win/core.c b/src/win/core.c index e53a0f8e2..68409e370 100644 --- a/src/win/core.c +++ b/src/win/core.c @@ -395,23 +395,28 @@ int uv_loop_fork(uv_loop_t* loop) { } +static int uv__loop_alive(const uv_loop_t* loop) { + return uv__has_active_handles(loop) || + uv__has_active_reqs(loop) || + loop->pending_reqs_tail != NULL || + loop->endgame_handles != NULL; +} + + +int uv_loop_alive(const uv_loop_t* loop) { + return uv__loop_alive(loop); +} + + int uv_backend_timeout(const uv_loop_t* loop) { - if (loop->stop_flag != 0) - return 0; - - if (!uv__has_active_handles(loop) && !uv__has_active_reqs(loop)) - return 0; - - if (loop->pending_reqs_tail) - return 0; - - if (loop->endgame_handles) - return 0; - - if (loop->idle_handles) - return 0; - - return uv__next_timeout(loop); + if (loop->stop_flag == 0 && + /* uv__loop_alive(loop) && */ + (uv__has_active_handles(loop) || uv__has_active_reqs(loop)) && + loop->pending_reqs_tail == NULL && + loop->idle_handles == NULL && + loop->endgame_handles == NULL) + return uv__next_timeout(loop); + return 0; } @@ -581,18 +586,6 @@ static void uv__poll(uv_loop_t* loop, DWORD timeout) { } -static int uv__loop_alive(const uv_loop_t* loop) { - return uv__has_active_handles(loop) || - uv__has_active_reqs(loop) || - loop->endgame_handles != NULL; -} - - -int uv_loop_alive(const uv_loop_t* loop) { - return uv__loop_alive(loop); -} - - int uv_run(uv_loop_t *loop, uv_run_mode mode) { DWORD timeout; int r; diff --git a/test/test-loop-time.c b/test/test-loop-time.c index a2db42cce..087720b9e 100644 --- a/test/test-loop-time.c +++ b/test/test-loop-time.c @@ -28,7 +28,7 @@ TEST_IMPL(loop_update_time) { start = uv_now(uv_default_loop()); while (uv_now(uv_default_loop()) - start < 1000) - ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_NOWAIT)); + ASSERT_EQ(0, uv_run(uv_default_loop(), UV_RUN_NOWAIT)); MAKE_VALGRIND_HAPPY(); return 0; @@ -43,20 +43,26 @@ TEST_IMPL(loop_backend_timeout) { uv_timer_t timer; int r; - r = uv_timer_init(loop, &timer); - ASSERT(r == 0); + /* The default loop has some internal watchers to initialize. */ + loop->active_handles++; + r = uv_run(loop, UV_RUN_NOWAIT); + ASSERT_EQ(r, 1); + loop->active_handles--; + ASSERT_EQ(uv_loop_alive(loop), 0); - ASSERT(!uv_loop_alive(loop)); - ASSERT(uv_backend_timeout(loop) == 0); + r = uv_timer_init(loop, &timer); + ASSERT_EQ(r, 0); + + ASSERT_EQ(uv_loop_alive(loop), 0); + ASSERT_EQ(uv_backend_timeout(loop), 0); r = uv_timer_start(&timer, cb, 1000, 0); /* 1 sec */ - ASSERT(r == 0); - ASSERT(uv_backend_timeout(loop) > 100); /* 0.1 sec */ - ASSERT(uv_backend_timeout(loop) <= 1000); /* 1 sec */ + ASSERT_EQ(r, 0); + ASSERT_EQ(uv_backend_timeout(loop), 1000); r = uv_run(loop, UV_RUN_DEFAULT); - ASSERT(r == 0); - ASSERT(uv_backend_timeout(loop) == 0); + ASSERT_EQ(r, 0); + ASSERT_EQ(uv_backend_timeout(loop), 0); MAKE_VALGRIND_HAPPY(); return 0;