From 85542b094c6f6b0be140fbe1e0967c6830226b08 Mon Sep 17 00:00:00 2001 From: Gabriel Schulhof Date: Fri, 13 Sep 2024 07:30:32 -0700 Subject: [PATCH] src: add Cleanable class to Environment We store a linked list of `Cleanable` objects on the `node::Environment` and invoke their `Clean()` method during env teardown. This eliminates the need for adding many cleanup hooks. PR-URL: https://github.com/nodejs/node/pull/54880 Reviewed-By: Yagiz Nizipli Reviewed-By: James M Snell Reviewed-By: Chengzhong Wu --- src/env.cc | 5 +++++ src/env.h | 17 +++++++++++++++++ src/node_buffer.cc | 21 +++++++++------------ 3 files changed, 31 insertions(+), 12 deletions(-) diff --git a/src/env.cc b/src/env.cc index 2c2cd663c8a672..38802b1e9acf9b 100644 --- a/src/env.cc +++ b/src/env.cc @@ -1237,6 +1237,11 @@ void Environment::RunCleanup() { // Defer the BaseObject cleanup after handles are cleaned up. CleanupHandles(); + while (!cleanable_queue_.IsEmpty()) { + Cleanable* cleanable = cleanable_queue_.PopFront(); + cleanable->Clean(); + } + while (!cleanup_queue_.empty() || principal_realm_->HasCleanupHooks() || native_immediates_.size() > 0 || native_immediates_threadsafe_.size() > 0 || diff --git a/src/env.h b/src/env.h index 57e0a71cbcecf0..30561ab7a24c73 100644 --- a/src/env.h +++ b/src/env.h @@ -599,6 +599,18 @@ void DefaultProcessExitHandlerInternal(Environment* env, ExitCode exit_code); v8::Maybe SpinEventLoopInternal(Environment* env); v8::Maybe EmitProcessExitInternal(Environment* env); +class Cleanable { + public: + virtual ~Cleanable() = default; + + protected: + ListNode cleanable_queue_; + + private: + virtual void Clean() = 0; + friend class Environment; +}; + /** * Environment is a per-isolate data structure that represents an execution * environment. Each environment has a principal realm. An environment can @@ -905,8 +917,12 @@ class Environment : public MemoryRetainer { typedef ListHead HandleWrapQueue; typedef ListHead ReqWrapQueue; + typedef ListHead CleanableQueue; inline HandleWrapQueue* handle_wrap_queue() { return &handle_wrap_queue_; } + inline CleanableQueue* cleanable_queue() { + return &cleanable_queue_; + } inline ReqWrapQueue* req_wrap_queue() { return &req_wrap_queue_; } // https://w3c.github.io/hr-time/#dfn-time-origin @@ -1182,6 +1198,7 @@ class Environment : public MemoryRetainer { // memory are predictable. For more information please refer to // `doc/contributing/node-postmortem-support.md` friend int GenDebugSymbols(); + CleanableQueue cleanable_queue_; HandleWrapQueue handle_wrap_queue_; ReqWrapQueue req_wrap_queue_; std::list handle_cleanup_queue_; diff --git a/src/node_buffer.cc b/src/node_buffer.cc index e6da36324362e8..d438b2bbdd89ac 100644 --- a/src/node_buffer.cc +++ b/src/node_buffer.cc @@ -81,7 +81,7 @@ using v8::Value; namespace { -class CallbackInfo { +class CallbackInfo : public Cleanable { public: static inline Local CreateTrackedArrayBuffer( Environment* env, @@ -94,7 +94,7 @@ class CallbackInfo { CallbackInfo& operator=(const CallbackInfo&) = delete; private: - static void CleanupHook(void* data); + void Clean(); inline void OnBackingStoreFree(); inline void CallAndResetCallback(); inline CallbackInfo(Environment* env, @@ -109,7 +109,6 @@ class CallbackInfo { Environment* const env_; }; - Local CallbackInfo::CreateTrackedArrayBuffer( Environment* env, char* data, @@ -149,25 +148,23 @@ CallbackInfo::CallbackInfo(Environment* env, data_(data), hint_(hint), env_(env) { - env->AddCleanupHook(CleanupHook, this); + env->cleanable_queue()->PushFront(this); env->isolate()->AdjustAmountOfExternalAllocatedMemory(sizeof(*this)); } -void CallbackInfo::CleanupHook(void* data) { - CallbackInfo* self = static_cast(data); - +void CallbackInfo::Clean() { { - HandleScope handle_scope(self->env_->isolate()); - Local ab = self->persistent_.Get(self->env_->isolate()); + HandleScope handle_scope(env_->isolate()); + Local ab = persistent_.Get(env_->isolate()); if (!ab.IsEmpty() && ab->IsDetachable()) { ab->Detach(Local()).Check(); - self->persistent_.Reset(); + persistent_.Reset(); } } // Call the callback in this case, but don't delete `this` yet because the // BackingStore deleter callback will do so later. - self->CallAndResetCallback(); + CallAndResetCallback(); } void CallbackInfo::CallAndResetCallback() { @@ -179,7 +176,7 @@ void CallbackInfo::CallAndResetCallback() { } if (callback != nullptr) { // Clean up all Environment-related state and run the callback. - env_->RemoveCleanupHook(CleanupHook, this); + cleanable_queue_.Remove(); int64_t change_in_bytes = -static_cast(sizeof(*this)); env_->isolate()->AdjustAmountOfExternalAllocatedMemory(change_in_bytes);