From cdc038ceb60cbdd14e98b69e5afc0671ff07c6fc Mon Sep 17 00:00:00 2001 From: Alexis Campailla Date: Tue, 17 Dec 2013 07:43:38 -0800 Subject: [PATCH] vm: fix race condition in timeout Eliminate a race condition between uv_async_send and the closing of the corresponding handle. Also made errors in Watchdog constructor call abort() Fixes #6088 --- src/node_watchdog.cc | 39 ++++++++++++++++----------------------- src/node_watchdog.h | 1 - 2 files changed, 16 insertions(+), 24 deletions(-) diff --git a/src/node_watchdog.cc b/src/node_watchdog.cc index 32c36ce..d5ad88f 100644 --- a/src/node_watchdog.cc +++ b/src/node_watchdog.cc @@ -20,6 +20,7 @@ // USE OR OTHER DEALINGS IN THE SOFTWARE. #include "node_watchdog.h" +#include "util.h" #include namespace node { @@ -27,27 +28,21 @@ namespace node { using v8::V8; -Watchdog::Watchdog(uint64_t ms) : thread_created_(false), destroyed_(false) { +Watchdog::Watchdog(uint64_t ms) : destroyed_(false) { loop_ = uv_loop_new(); - if (!loop_) - return; + CHECK(loop_); int rc = uv_async_init(loop_, &async_, &Watchdog::Async); - assert(rc == 0); + CHECK(0 == rc); // NOLINT(readability/check) rc = uv_timer_init(loop_, &timer_); - assert(rc == 0); + CHECK(0 == rc); // NOLINT(readability/check) rc = uv_timer_start(&timer_, &Watchdog::Timer, ms, 0); - if (rc) { - return; - } + CHECK(0 == rc); // NOLINT(readability/check) rc = uv_thread_create(&thread_, &Watchdog::Run, this); - if (rc) { - return; - } - thread_created_ = true; + CHECK(0 == rc); // NOLINT(readability/check) } @@ -66,14 +61,15 @@ void Watchdog::Destroy() { return; } - if (thread_created_) { - uv_async_send(&async_); - uv_thread_join(&thread_); - } + uv_async_send(&async_); + uv_thread_join(&thread_); - if (loop_) { - uv_loop_delete(loop_); - } + uv_close(reinterpret_cast(&async_), NULL); + + // UV_RUN_DEFAULT so that libuv has a chance to clean up. + uv_run(loop_, UV_RUN_DEFAULT); + + uv_loop_delete(loop_); destroyed_ = true; } @@ -86,11 +82,8 @@ void Watchdog::Run(void* arg) { uv_run(wd->loop_, UV_RUN_ONCE); // Loop ref count reaches zero when both handles are closed. - uv_close(reinterpret_cast(&wd->async_), NULL); + // Close the timer handle on this side and let Destroy() close async_ uv_close(reinterpret_cast(&wd->timer_), NULL); - - // UV_RUN_DEFAULT so that libuv has a chance to clean up. - uv_run(wd->loop_, UV_RUN_DEFAULT); } diff --git a/src/node_watchdog.h b/src/node_watchdog.h index 9ac82cf..87adf19 100644 --- a/src/node_watchdog.h +++ b/src/node_watchdog.h @@ -45,7 +45,6 @@ class Watchdog { uv_loop_t* loop_; uv_async_t async_; uv_timer_t timer_; - bool thread_created_; bool destroyed_; }; -- 2.7.4