Skip to content
This repository has been archived by the owner on Apr 22, 2023. It is now read-only.

Commit

Permalink
vm: fix race condition in timeout
Browse files Browse the repository at this point in the history
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
  • Loading branch information
orangemocha authored and tjfontaine committed Dec 18, 2013
1 parent 95ee84f commit cdc038c
Show file tree
Hide file tree
Showing 2 changed files with 16 additions and 24 deletions.
39 changes: 16 additions & 23 deletions src/node_watchdog.cc
Original file line number Diff line number Diff line change
Expand Up @@ -20,34 +20,29 @@
// USE OR OTHER DEALINGS IN THE SOFTWARE.

#include "node_watchdog.h"
#include "util.h"
#include <assert.h>

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


Expand All @@ -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<uv_handle_t*>(&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;
}
Expand All @@ -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<uv_handle_t*>(&wd->async_), NULL);
// Close the timer handle on this side and let Destroy() close async_
uv_close(reinterpret_cast<uv_handle_t*>(&wd->timer_), NULL);

// UV_RUN_DEFAULT so that libuv has a chance to clean up.
uv_run(wd->loop_, UV_RUN_DEFAULT);
}


Expand Down
1 change: 0 additions & 1 deletion src/node_watchdog.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ class Watchdog {
uv_loop_t* loop_;
uv_async_t async_;
uv_timer_t timer_;
bool thread_created_;
bool destroyed_;
};

Expand Down

0 comments on commit cdc038c

Please sign in to comment.