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
This commit is contained in:
Saúl Ibarra Corretgé 2012-12-18 16:10:11 +01:00 committed by Bert Belder
parent dc559a5ce6
commit 0820be7008
8 changed files with 121 additions and 71 deletions

View File

@ -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

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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)

46
test/test-run-nowait.c Normal file
View File

@ -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;
}

View File

@ -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();

1
uv.gyp
View File

@ -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',