From 0820be70084a44792d96cfbd80b6e97159c44439 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Tue, 18 Dec 2012 16:10:11 +0100 Subject: [PATCH] Implemented uv_run2 Allows for running the event loop in 3 modes: * default: loop runs until the refcount drops to zero * once: poll for events only once and block until one is handled * nowait: poll for events only once but don't block if there are no pending events --- include/uv.h | 23 +++++++++--- src/unix/core.c | 32 ++++++++-------- src/win/core.c | 84 +++++++++++++++++++----------------------- test/test-embed.c | 2 +- test/test-list.h | 2 + test/test-run-nowait.c | 46 +++++++++++++++++++++++ test/test-run-once.c | 2 +- uv.gyp | 1 + 8 files changed, 121 insertions(+), 71 deletions(-) create mode 100644 test/test-run-nowait.c diff --git a/include/uv.h b/include/uv.h index 57ce8ae5..aa71405f 100644 --- a/include/uv.h +++ b/include/uv.h @@ -221,6 +221,13 @@ typedef struct uv_cpu_info_s uv_cpu_info_t; typedef struct uv_interface_address_s uv_interface_address_t; +typedef enum { + UV_RUN_DEFAULT = 0, + UV_RUN_ONCE, + UV_RUN_NOWAIT +} uv_run_mode; + + /* * This function must be called before any other functions in libuv. * @@ -244,12 +251,18 @@ UV_EXTERN uv_loop_t* uv_default_loop(void); UV_EXTERN int uv_run(uv_loop_t*); /* - * Poll for new events once. Note that this function blocks if there are no - * pending events. Returns zero when done (no active handles or requests left), - * or non-zero if more events are expected (meaning you should call - * uv_run_once() again sometime in the future). + * This function runs the event loop. It will act differently depending on the + * specified mode: + * - UV_RUN_DEFAULT: Runs the event loop until the reference count drops to + * zero. Always returns zero. + * - UV_RUN_ONCE: Poll for new events once. Note that this function blocks if + * there are no pending events. Returns zero when done (no active handles + * or requests left), or non-zero if more events are expected (meaning you + * should run the event loop again sometime in the future). + * - UV_RUN_NOWAIT: Poll for new events once but don't block if there are no + * pending events. */ -UV_EXTERN int uv_run_once(uv_loop_t*); +UV_EXTERN int uv_run2(uv_loop_t*, uv_run_mode mode); /* * Manually modify the event loop's reference count. Useful if the user wants diff --git a/src/unix/core.c b/src/unix/core.c index b0686ce0..196d2668 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -267,27 +267,25 @@ int uv_backend_timeout(const uv_loop_t* loop) { } -static int uv__run(uv_loop_t* loop) { - uv_update_time(loop); - uv__run_timers(loop); - uv__run_idle(loop); - uv__run_prepare(loop); - uv__run_pending(loop); - uv__io_poll(loop, uv_backend_timeout(loop)); - uv__run_check(loop); - uv__run_closing_handles(loop); - return uv__has_active_handles(loop) || uv__has_active_reqs(loop); +int uv_run2(uv_loop_t* loop, uv_run_mode mode) { + int r; + do { + uv_update_time(loop); + uv__run_timers(loop); + uv__run_idle(loop); + uv__run_prepare(loop); + uv__run_pending(loop); + uv__io_poll(loop, (mode & UV_RUN_NOWAIT ? 0 : uv_backend_timeout(loop))); + uv__run_check(loop); + uv__run_closing_handles(loop); + r = uv__has_active_handles(loop) || uv__has_active_reqs(loop); + } while (r && !(mode & (UV_RUN_ONCE | UV_RUN_NOWAIT))); + return r; } int uv_run(uv_loop_t* loop) { - while (uv__run(loop)); - return 0; -} - - -int uv_run_once(uv_loop_t* loop) { - return uv__run(loop); + return uv_run2(loop, UV_RUN_DEFAULT); } diff --git a/src/win/core.c b/src/win/core.c index 3df3399b..0876feda 100644 --- a/src/win/core.c +++ b/src/win/core.c @@ -252,57 +252,47 @@ static void uv_poll_ex(uv_loop_t* loop, int block) { !ngx_queue_empty(&(loop)->active_reqs) || \ (loop)->endgame_handles != NULL) -#define UV_LOOP_ONCE(loop, poll) \ - do { \ - uv_update_time((loop)); \ - uv_process_timers((loop)); \ - \ - /* Call idle callbacks if nothing to do. */ \ - if ((loop)->pending_reqs_tail == NULL && \ - (loop)->endgame_handles == NULL) { \ - uv_idle_invoke((loop)); \ - } \ - \ - uv_process_reqs((loop)); \ - uv_process_endgames((loop)); \ - \ - if (!UV_LOOP_ALIVE((loop))) { \ - break; \ - } \ - \ - uv_prepare_invoke((loop)); \ - \ - poll((loop), (loop)->idle_handles == NULL && \ - (loop)->pending_reqs_tail == NULL && \ - (loop)->endgame_handles == NULL && \ - UV_LOOP_ALIVE((loop))); \ - \ - uv_check_invoke((loop)); \ - } while (0); +int uv_run2(uv_loop_t *loop, uv_run_mode mode) { + int r; + void (*poll)(uv_loop_t* loop, int block); -#define UV_LOOP(loop, poll) \ - while (UV_LOOP_ALIVE((loop))) { \ - UV_LOOP_ONCE(loop, poll) \ + if (pGetQueuedCompletionStatusEx) + poll = &uv_poll_ex; + else + poll = &uv_poll; + + r = UV_LOOP_ALIVE(loop); + while (r) { + uv_update_time(loop); + uv_process_timers(loop); + + /* Call idle callbacks if nothing to do. */ + if (loop->pending_reqs_tail == NULL && + loop->endgame_handles == NULL) { + uv_idle_invoke(loop); + } + + uv_process_reqs(loop); + uv_process_endgames(loop); + + uv_prepare_invoke(loop); + + (*poll)(loop, loop->idle_handles == NULL && + loop->pending_reqs_tail == NULL && + loop->endgame_handles == NULL && + UV_LOOP_ALIVE(loop) && + !(mode & UV_RUN_NOWAIT)); + + uv_check_invoke(loop); + r = UV_LOOP_ALIVE(loop); + + if (mode & (UV_RUN_ONCE | UV_RUN_NOWAIT)) + break; } - - -int uv_run_once(uv_loop_t* loop) { - if (pGetQueuedCompletionStatusEx) { - UV_LOOP_ONCE(loop, uv_poll_ex); - } else { - UV_LOOP_ONCE(loop, uv_poll); - } - return UV_LOOP_ALIVE(loop); + return r; } int uv_run(uv_loop_t* loop) { - if (pGetQueuedCompletionStatusEx) { - UV_LOOP(loop, uv_poll_ex); - } else { - UV_LOOP(loop, uv_poll); - } - - assert(!UV_LOOP_ALIVE((loop))); - return 0; + return uv_run2(loop, UV_RUN_DEFAULT); } diff --git a/test/test-embed.c b/test/test-embed.c index e635596e..547bbfb1 100644 --- a/test/test-embed.c +++ b/test/test-embed.c @@ -84,7 +84,7 @@ static void embed_thread_runner(void* arg) { static void embed_cb(uv_async_t* async, int status) { - uv_run_once(uv_default_loop()); + uv_run2(uv_default_loop(), UV_RUN_ONCE); uv_sem_post(&embed_sem); } diff --git a/test/test-list.h b/test/test-list.h index 9c59a2d4..45c4b6c7 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -22,6 +22,7 @@ TEST_DECLARE (platform_output) TEST_DECLARE (callback_order) TEST_DECLARE (run_once) +TEST_DECLARE (run_nowait) TEST_DECLARE (barrier_1) TEST_DECLARE (barrier_2) TEST_DECLARE (barrier_3) @@ -227,6 +228,7 @@ TASK_LIST_START TEST_ENTRY (callback_order) #endif TEST_ENTRY (run_once) + TEST_ENTRY (run_nowait) TEST_ENTRY (barrier_1) TEST_ENTRY (barrier_2) TEST_ENTRY (barrier_3) diff --git a/test/test-run-nowait.c b/test/test-run-nowait.c new file mode 100644 index 00000000..fe8dd894 --- /dev/null +++ b/test/test-run-nowait.c @@ -0,0 +1,46 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" + +static uv_timer_t timer_handle; +static int timer_called = 0; + + +static void timer_cb(uv_timer_t* handle, int status) { + ASSERT(handle == &timer_handle); + ASSERT(status == 0); + timer_called = 1; +} + + +TEST_IMPL(run_nowait) { + int r; + uv_timer_init(uv_default_loop(), &timer_handle); + uv_timer_start(&timer_handle, timer_cb, 100, 100); + + r = uv_run2(uv_default_loop(), UV_RUN_NOWAIT); + ASSERT(r != 0); + ASSERT(timer_called == 0); + + return 0; +} diff --git a/test/test-run-once.c b/test/test-run-once.c index b425a423..ecd82a2c 100644 --- a/test/test-run-once.c +++ b/test/test-run-once.c @@ -41,7 +41,7 @@ TEST_IMPL(run_once) { uv_idle_init(uv_default_loop(), &idle_handle); uv_idle_start(&idle_handle, idle_cb); - while (uv_run_once(uv_default_loop())); + while (uv_run2(uv_default_loop(), UV_RUN_ONCE)); ASSERT(idle_counter == NUM_TICKS); MAKE_VALGRIND_HAPPY(); diff --git a/uv.gyp b/uv.gyp index ac6f7f04..9484b35c 100644 --- a/uv.gyp +++ b/uv.gyp @@ -275,6 +275,7 @@ 'test/test-poll-close.c', 'test/test-process-title.c', 'test/test-ref.c', + 'test/test-run-nowait.c', 'test/test-run-once.c', 'test/test-semaphore.c', 'test/test-shutdown-close.c',