From bb3d1e24da288db876dcbfa4e983c9ceeb583890 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Wed, 16 Jan 2013 09:36:20 +0100 Subject: [PATCH] unix, windows: add uv_stop, stop running event loop --- build.mk | 1 + include/uv.h | 10 ++++++++ src/unix/core.c | 12 ++++++++-- src/unix/loop.c | 1 + src/uv-common.c | 5 ++++ src/win/core.c | 5 ++++ test/test-list.h | 2 ++ test/test-loop-stop.c | 55 +++++++++++++++++++++++++++++++++++++++++++ uv.gyp | 1 + 9 files changed, 90 insertions(+), 2 deletions(-) create mode 100644 test/test-loop-stop.c diff --git a/build.mk b/build.mk index 88de949d..a19db494 100644 --- a/build.mk +++ b/build.mk @@ -85,6 +85,7 @@ TESTS= \ test/test-ipc.o \ test/test-ipc-send-recv.o \ test/test-loop-handles.o \ + test/test-loop-stop.o \ test/test-multiple-listen.o \ test/test-mutexes.o \ test/test-pass-always.o \ diff --git a/include/uv.h b/include/uv.h index 4d6a2e80..de375d4b 100644 --- a/include/uv.h +++ b/include/uv.h @@ -258,6 +258,14 @@ UV_EXTERN uv_loop_t* uv_default_loop(void); */ UV_EXTERN int uv_run(uv_loop_t*, uv_run_mode mode); +/* + * This function will stop the event loop by forcing uv_run to end + * as soon as possible, but not sooner than the next loop iteration. + * If this function was called before blocking for i/o, the loop won't + * block for i/o on this iteration. + */ +UV_EXTERN void uv_stop(uv_loop_t*); + /* * Manually modify the event loop's reference count. Useful if the user wants * to have a handle or timeout that doesn't keep the loop alive. @@ -1934,6 +1942,8 @@ struct uv_loop_s { unsigned int active_handles; ngx_queue_t handle_queue; ngx_queue_t active_reqs; + /* Internal flag to signal loop stop */ + unsigned int stop_flag; UV_LOOP_PRIVATE_FIELDS }; diff --git a/src/unix/core.c b/src/unix/core.c index e5c9a4d9..97101068 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -280,18 +280,26 @@ static int uv__loop_alive(uv_loop_t* loop) { int uv_run(uv_loop_t* loop, uv_run_mode mode) { - int r; + int r, timeout; if (!uv__loop_alive(loop)) return 0; do { + if (loop->stop_flag) { + loop->stop_flag = 0; + return uv__loop_alive(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, (mode & UV_RUN_NOWAIT ? 0 : uv_backend_timeout(loop))); + if (mode & UV_RUN_NOWAIT || loop->stop_flag) + timeout = 0; + else + timeout = uv_backend_timeout(loop); + uv__io_poll(loop, timeout); uv__run_check(loop); uv__run_closing_handles(loop); r = uv__loop_alive(loop); diff --git a/src/unix/loop.c b/src/unix/loop.c index 61360727..75b0702a 100644 --- a/src/unix/loop.c +++ b/src/unix/loop.c @@ -57,6 +57,7 @@ int uv__loop_init(uv_loop_t* loop, int default_loop) { loop->emfile_fd = -1; loop->timer_counter = 0; + loop->stop_flag = 0; if (uv__platform_loop_init(loop, default_loop)) return -1; diff --git a/src/uv-common.c b/src/uv-common.c index ae2ca714..660c33ed 100644 --- a/src/uv-common.c +++ b/src/uv-common.c @@ -377,3 +377,8 @@ void uv_ref(uv_handle_t* handle) { void uv_unref(uv_handle_t* handle) { uv__handle_unref(handle); } + + +void uv_stop(uv_loop_t* loop) { + loop->stop_flag = 1; +} diff --git a/src/win/core.c b/src/win/core.c index d1343df1..ca566c03 100644 --- a/src/win/core.c +++ b/src/win/core.c @@ -270,6 +270,10 @@ int uv_run(uv_loop_t *loop, uv_run_mode mode) { return 0; do { + if (loop->stop_flag) { + loop->stop_flag = 0; + return uv__loop_alive(loop); + } uv_update_time(loop); uv_process_timers(loop); @@ -287,6 +291,7 @@ int uv_run(uv_loop_t *loop, uv_run_mode mode) { (*poll)(loop, loop->idle_handles == NULL && loop->pending_reqs_tail == NULL && loop->endgame_handles == NULL && + !loop->stop_flag && (loop->active_handles > 0 || !ngx_queue_empty(&loop->active_reqs)) && !(mode & UV_RUN_NOWAIT)); diff --git a/test/test-list.h b/test/test-list.h index 6c7da04c..2341463a 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -23,6 +23,7 @@ TEST_DECLARE (platform_output) TEST_DECLARE (callback_order) TEST_DECLARE (run_once) TEST_DECLARE (run_nowait) +TEST_DECLARE (loop_stop) TEST_DECLARE (barrier_1) TEST_DECLARE (barrier_2) TEST_DECLARE (barrier_3) @@ -230,6 +231,7 @@ TASK_LIST_START #endif TEST_ENTRY (run_once) TEST_ENTRY (run_nowait) + TEST_ENTRY (loop_stop) TEST_ENTRY (barrier_1) TEST_ENTRY (barrier_2) TEST_ENTRY (barrier_3) diff --git a/test/test-loop-stop.c b/test/test-loop-stop.c new file mode 100644 index 00000000..75ff9153 --- /dev/null +++ b/test/test-loop-stop.c @@ -0,0 +1,55 @@ +/* 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 int num_ticks = 10; + + +static void timer_cb(uv_timer_t* handle, int status) { + ASSERT(handle == &timer_handle); + ASSERT(status == 0); + timer_called++; + if (timer_called == 1) + uv_stop(uv_default_loop()); + else if (timer_called == num_ticks) + uv_timer_stop(handle); +} + + +TEST_IMPL(loop_stop) { + int r; + uv_timer_init(uv_default_loop(), &timer_handle); + uv_timer_start(&timer_handle, timer_cb, 100, 100); + + r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); + ASSERT(r != 0); + ASSERT(timer_called == 1); + + r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); + ASSERT(r == 0); + ASSERT(timer_called == 10); + + return 0; +} diff --git a/uv.gyp b/uv.gyp index e3443b26..55f1e239 100644 --- a/uv.gyp +++ b/uv.gyp @@ -280,6 +280,7 @@ 'test/test-ipc-send-recv.c', 'test/test-list.h', 'test/test-loop-handles.c', + 'test/test-loop-stop.c', 'test/test-walk-handles.c', 'test/test-multiple-listen.c', 'test/test-pass-always.c',