src: use cleanup hooks to tear down BaseObjects
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: https://github.com/ayojs/ayo/pull/88 PR-URL: https://github.com/nodejs/node/pull/19377 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: James M Snell <jasnell@gmail.com>
This commit is contained in:
parent
1db0039c50
commit
61fd027096
@ -37,10 +37,13 @@ BaseObject::BaseObject(Environment* env, v8::Local<v8::Object> object)
|
|||||||
CHECK_EQ(false, object.IsEmpty());
|
CHECK_EQ(false, object.IsEmpty());
|
||||||
CHECK_GT(object->InternalFieldCount(), 0);
|
CHECK_GT(object->InternalFieldCount(), 0);
|
||||||
object->SetAlignedPointerInInternalField(0, static_cast<void*>(this));
|
object->SetAlignedPointerInInternalField(0, static_cast<void*>(this));
|
||||||
|
env_->AddCleanupHook(DeleteMe, static_cast<void*>(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
BaseObject::~BaseObject() {
|
BaseObject::~BaseObject() {
|
||||||
|
env_->RemoveCleanupHook(DeleteMe, static_cast<void*>(this));
|
||||||
|
|
||||||
if (persistent_handle_.IsEmpty()) {
|
if (persistent_handle_.IsEmpty()) {
|
||||||
// This most likely happened because the weak callback below cleared it.
|
// This most likely happened because the weak callback below cleared it.
|
||||||
return;
|
return;
|
||||||
@ -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() {
|
void BaseObject::MakeWeak() {
|
||||||
persistent_handle_.SetWeak(
|
persistent_handle_.SetWeak(
|
||||||
this,
|
this,
|
||||||
|
@ -71,6 +71,8 @@ class BaseObject {
|
|||||||
private:
|
private:
|
||||||
BaseObject();
|
BaseObject();
|
||||||
|
|
||||||
|
static inline void DeleteMe(void* data);
|
||||||
|
|
||||||
// persistent_handle_ needs to be at a fixed offset from the start of the
|
// 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
|
// class because it is used by src/node_postmortem_metadata.cc to calculate
|
||||||
// offsets and generate debug symbols for BaseObject, which assumes that the
|
// offsets and generate debug symbols for BaseObject, which assumes that the
|
||||||
|
@ -133,6 +133,10 @@ Environment::Environment(IsolateData* isolate_data,
|
|||||||
}
|
}
|
||||||
|
|
||||||
Environment::~Environment() {
|
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());
|
v8::HandleScope handle_scope(isolate());
|
||||||
|
|
||||||
#if HAVE_INSPECTOR
|
#if HAVE_INSPECTOR
|
||||||
@ -245,6 +249,8 @@ void Environment::CleanupHandles() {
|
|||||||
!handle_wrap_queue_.IsEmpty()) {
|
!handle_wrap_queue_.IsEmpty()) {
|
||||||
uv_run(event_loop(), UV_RUN_ONCE);
|
uv_run(event_loop(), UV_RUN_ONCE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
file_handle_read_wrap_freelist_.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Environment::StartProfilerIdleNotifier() {
|
void Environment::StartProfilerIdleNotifier() {
|
||||||
|
@ -576,6 +576,8 @@ std::unique_ptr<InspectorSession> Agent::Connect(
|
|||||||
|
|
||||||
void Agent::WaitForDisconnect() {
|
void Agent::WaitForDisconnect() {
|
||||||
CHECK_NE(client_, nullptr);
|
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());
|
client_->contextDestroyed(parent_env_->context());
|
||||||
if (io_ != nullptr) {
|
if (io_ != nullptr) {
|
||||||
io_->WaitForDisconnect();
|
io_->WaitForDisconnect();
|
||||||
|
@ -4550,12 +4550,13 @@ inline int Start(Isolate* isolate, IsolateData* isolate_data,
|
|||||||
|
|
||||||
const int exit_code = EmitExit(&env);
|
const int exit_code = EmitExit(&env);
|
||||||
|
|
||||||
|
WaitForInspectorDisconnect(&env);
|
||||||
|
|
||||||
env.RunCleanup();
|
env.RunCleanup();
|
||||||
RunAtExit(&env);
|
RunAtExit(&env);
|
||||||
|
|
||||||
v8_platform.DrainVMTasks(isolate);
|
v8_platform.DrainVMTasks(isolate);
|
||||||
v8_platform.CancelVMTasks(isolate);
|
v8_platform.CancelVMTasks(isolate);
|
||||||
WaitForInspectorDisconnect(&env);
|
|
||||||
#if defined(LEAK_SANITIZER)
|
#if defined(LEAK_SANITIZER)
|
||||||
__lsan_do_leak_check();
|
__lsan_do_leak_check();
|
||||||
#endif
|
#endif
|
||||||
|
@ -26,7 +26,6 @@ ReqWrap<T>::ReqWrap(Environment* env,
|
|||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
ReqWrap<T>::~ReqWrap() {
|
ReqWrap<T>::~ReqWrap() {
|
||||||
CHECK_EQ(req_.data, this); // Assert that someone has called Dispatched().
|
|
||||||
CHECK_EQ(false, persistent().IsEmpty());
|
CHECK_EQ(false, persistent().IsEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user