Skip to content

Commit

Permalink
src: use cleanup hooks to tear down BaseObjects
Browse files Browse the repository at this point in the history
Clean up after `BaseObject` instances when the `Environment`
is being shut down. This takes care of closing non-libuv resources
like `zlib` instances, which do not require asynchronous shutdown.

Many thanks for Stephen Belanger, Timothy Gu and Alexey Orlenko for
reviewing the original version of this commit in the Ayo.js project.

Refs: ayojs/ayo#88
PR-URL: #19377
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: James M Snell <jasnell@gmail.com>
  • Loading branch information
addaleax committed May 14, 2018
1 parent 8995408 commit 9e2554c
Show file tree
Hide file tree
Showing 6 changed files with 21 additions and 2 deletions.
9 changes: 9 additions & 0 deletions src/base_object-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,13 @@ BaseObject::BaseObject(Environment* env, v8::Local<v8::Object> object)
CHECK_EQ(false, object.IsEmpty());
CHECK_GT(object->InternalFieldCount(), 0);
object->SetAlignedPointerInInternalField(0, static_cast<void*>(this));
env_->AddCleanupHook(DeleteMe, static_cast<void*>(this));
}


BaseObject::~BaseObject() {
env_->RemoveCleanupHook(DeleteMe, static_cast<void*>(this));

if (persistent_handle_.IsEmpty()) {
// This most likely happened because the weak callback below cleared it.
return;
Expand Down Expand Up @@ -80,6 +83,12 @@ T* BaseObject::FromJSObject(v8::Local<v8::Object> object) {
}


void BaseObject::DeleteMe(void* data) {
BaseObject* self = static_cast<BaseObject*>(data);
delete self;
}


void BaseObject::MakeWeak() {
persistent_handle_.SetWeak(
this,
Expand Down
2 changes: 2 additions & 0 deletions src/base_object.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ class BaseObject {
private:
BaseObject();

static inline void DeleteMe(void* data);

// persistent_handle_ needs to be at a fixed offset from the start of the
// class because it is used by src/node_postmortem_metadata.cc to calculate
// offsets and generate debug symbols for BaseObject, which assumes that the
Expand Down
6 changes: 6 additions & 0 deletions src/env.cc
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,10 @@ Environment::Environment(IsolateData* isolate_data,
}

Environment::~Environment() {
// Make sure there are no re-used libuv wrapper objects.
// CleanupHandles() should have removed all of them.
CHECK(file_handle_read_wrap_freelist_.empty());

v8::HandleScope handle_scope(isolate());

#if HAVE_INSPECTOR
Expand Down Expand Up @@ -245,6 +249,8 @@ void Environment::CleanupHandles() {
!handle_wrap_queue_.IsEmpty()) {
uv_run(event_loop(), UV_RUN_ONCE);
}

file_handle_read_wrap_freelist_.clear();
}

void Environment::StartProfilerIdleNotifier() {
Expand Down
2 changes: 2 additions & 0 deletions src/inspector_agent.cc
Original file line number Diff line number Diff line change
Expand Up @@ -576,6 +576,8 @@ std::unique_ptr<InspectorSession> Agent::Connect(

void Agent::WaitForDisconnect() {
CHECK_NE(client_, nullptr);
// TODO(addaleax): Maybe this should use an at-exit hook for the Environment
// or something similar?
client_->contextDestroyed(parent_env_->context());
if (io_ != nullptr) {
io_->WaitForDisconnect();
Expand Down
3 changes: 2 additions & 1 deletion src/node.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4578,12 +4578,13 @@ inline int Start(Isolate* isolate, IsolateData* isolate_data,

const int exit_code = EmitExit(&env);

WaitForInspectorDisconnect(&env);

env.RunCleanup();
RunAtExit(&env);

v8_platform.DrainVMTasks(isolate);
v8_platform.CancelVMTasks(isolate);
WaitForInspectorDisconnect(&env);
#if defined(LEAK_SANITIZER)
__lsan_do_leak_check();
#endif
Expand Down
1 change: 0 additions & 1 deletion src/req_wrap-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ ReqWrap<T>::ReqWrap(Environment* env,

template <typename T>
ReqWrap<T>::~ReqWrap() {
CHECK_EQ(req_.data, this); // Assert that someone has called Dispatched().
CHECK_EQ(false, persistent().IsEmpty());
}

Expand Down

0 comments on commit 9e2554c

Please sign in to comment.