Skip to content

Commit

Permalink
src: use libuv's refcounting directly
Browse files Browse the repository at this point in the history
Don't implement an additional reference counting scheme on top of libuv.
Libuv is the canonical source for that information so use it directly.

PR-URL: #6395
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
  • Loading branch information
bnoordhuis authored and evanlucas committed May 17, 2016
1 parent 2000072 commit 965274d
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 31 deletions.
42 changes: 18 additions & 24 deletions src/handle_wrap.cc
Original file line number Diff line number Diff line change
Expand Up @@ -21,28 +21,25 @@ using v8::Value;
void HandleWrap::Ref(const FunctionCallbackInfo<Value>& args) {
HandleWrap* wrap = Unwrap<HandleWrap>(args.Holder());

if (IsAlive(wrap)) {
uv_ref(wrap->handle__);
wrap->flags_ &= ~kUnref;
}
if (IsAlive(wrap))
uv_ref(wrap->GetHandle());
}


void HandleWrap::Unref(const FunctionCallbackInfo<Value>& args) {
HandleWrap* wrap = Unwrap<HandleWrap>(args.Holder());

if (IsAlive(wrap)) {
uv_unref(wrap->handle__);
wrap->flags_ |= kUnref;
}
if (IsAlive(wrap))
uv_unref(wrap->GetHandle());
}


void HandleWrap::Unrefed(const FunctionCallbackInfo<Value>& args) {
HandleWrap* wrap = Unwrap<HandleWrap>(args.Holder());

bool unrefed = wrap->flags_ & kUnref == 1;
args.GetReturnValue().Set(unrefed);
// XXX(bnoordhuis) It's debatable whether a nullptr wrap should count
// as having a reference count but it's compatible with the logic that
// it replaces.
args.GetReturnValue().Set(wrap == nullptr || !HasRef(wrap));
}


Expand All @@ -51,17 +48,17 @@ void HandleWrap::Close(const FunctionCallbackInfo<Value>& args) {

HandleWrap* wrap = Unwrap<HandleWrap>(args.Holder());

// guard against uninitialized handle or double close
// Guard against uninitialized handle or double close.
if (!IsAlive(wrap))
return;

CHECK_EQ(false, wrap->persistent().IsEmpty());
uv_close(wrap->handle__, OnClose);
wrap->handle__ = nullptr;
wrap->state_ = kClosing;

if (args[0]->IsFunction()) {
wrap->object()->Set(env->onclose_string(), args[0]);
wrap->flags_ |= kCloseCallback;
wrap->state_ = kClosingWithCallback;
}
}

Expand All @@ -72,7 +69,7 @@ HandleWrap::HandleWrap(Environment* env,
AsyncWrap::ProviderType provider,
AsyncWrap* parent)
: AsyncWrap(env, object, provider, parent),
flags_(0),
state_(kInitialized),
handle__(handle) {
handle__->data = this;
HandleScope scope(env->isolate());
Expand All @@ -90,22 +87,19 @@ void HandleWrap::OnClose(uv_handle_t* handle) {
HandleWrap* wrap = static_cast<HandleWrap*>(handle->data);
Environment* env = wrap->env();
HandleScope scope(env->isolate());
Context::Scope context_scope(env->context());

// The wrap object should still be there.
CHECK_EQ(wrap->persistent().IsEmpty(), false);
CHECK(wrap->state_ >= kClosing && wrap->state_ <= kClosingWithCallback);

// But the handle pointer should be gone.
CHECK_EQ(wrap->handle__, nullptr);
const bool have_close_callback = (wrap->state_ == kClosingWithCallback);
wrap->state_ = kClosed;

HandleScope handle_scope(env->isolate());
Context::Scope context_scope(env->context());
Local<Object> object = wrap->object();

if (wrap->flags_ & kCloseCallback) {
if (have_close_callback)
wrap->MakeCallback(env->onclose_string(), 0, nullptr);
}

object->SetAlignedPointerInInternalField(0, nullptr);
wrap->object()->SetAlignedPointerInInternalField(0, nullptr);
wrap->persistent().Reset();
delete wrap;
}
Expand Down
17 changes: 11 additions & 6 deletions src/handle_wrap.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,15 @@ class HandleWrap : public AsyncWrap {
static void Unrefed(const v8::FunctionCallbackInfo<v8::Value>& args);

static inline bool IsAlive(const HandleWrap* wrap) {
return wrap != nullptr && wrap->GetHandle() != nullptr;
// XXX(bnoordhuis) It's debatable whether only kInitialized should
// count as alive but it's compatible with the check that it replaces.
return wrap != nullptr && wrap->state_ == kInitialized;
}

static inline bool HasRef(const HandleWrap* wrap) {
return wrap != nullptr &&
wrap->state_ != kClosed &&
uv_has_ref(wrap->GetHandle());
}

inline uv_handle_t* GetHandle() const { return handle__; }
Expand All @@ -56,13 +64,10 @@ class HandleWrap : public AsyncWrap {
friend void GetActiveHandles(const v8::FunctionCallbackInfo<v8::Value>&);
static void OnClose(uv_handle_t* handle);
ListNode<HandleWrap> handle_wrap_queue_;
unsigned int flags_;
enum { kInitialized, kClosing, kClosingWithCallback, kClosed } state_;
// Using double underscore due to handle_ member in tcp_wrap. Probably
// tcp_wrap should rename it's member to 'handle'.
uv_handle_t* handle__;

static const unsigned int kUnref = 1;
static const unsigned int kCloseCallback = 2;
uv_handle_t* const handle__;
};


Expand Down
2 changes: 1 addition & 1 deletion src/node.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1726,7 +1726,7 @@ void GetActiveHandles(const FunctionCallbackInfo<Value>& args) {
Local<String> owner_sym = env->owner_string();

for (auto w : *env->handle_wrap_queue()) {
if (w->persistent().IsEmpty() || (w->flags_ & HandleWrap::kUnref))
if (w->persistent().IsEmpty() || !HandleWrap::HasRef(w))
continue;
Local<Object> object = w->object();
Local<Value> owner = object->Get(owner_sym);
Expand Down

0 comments on commit 965274d

Please sign in to comment.