summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAnna Henningsen <anna@addaleax.net>2019-03-01 23:35:54 +0100
committerAnna Henningsen <anna@addaleax.net>2019-03-13 00:12:56 +0000
commit6d9aa73b1f2a0b053e39d743b1ddf382d35adfad (patch)
tree3254de3bb6292f36c4458f06f28a663614df924f /src
parent377c5835e8bfcd04273f24a244b2ba4aff76a27c (diff)
downloadandroid-node-v8-6d9aa73b1f2a0b053e39d743b1ddf382d35adfad.tar.gz
android-node-v8-6d9aa73b1f2a0b053e39d743b1ddf382d35adfad.tar.bz2
android-node-v8-6d9aa73b1f2a0b053e39d743b1ddf382d35adfad.zip
src: clean up MultiIsolatePlatform interface
- Since this was introduced, V8 has effectively started requiring that the platform knows of the `Isolate*` before we (or an embedder) create our `IsolateData` structure; therefore, (un)registering it from the `IsolateData` constructor/destructor doesn’t make much sense anymore. - Instead, we can require that the register/unregister functions are only called once, simplifying the implementation a bit. - Add a callback that we can use to know when the platform has cleaned up its resources associated with a given `Isolate`. In particular, this means that in the Worker code, we don’t need to rely on what are essentially guesses about the number of event loop turns that we need in order to have everything cleaned up. PR-URL: https://github.com/nodejs/node/pull/26384 Reviewed-By: Daniel Bevenius <daniel.bevenius@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com>
Diffstat (limited to 'src')
-rw-r--r--src/env.cc8
-rw-r--r--src/env.h1
-rw-r--r--src/node.h14
-rw-r--r--src/node_platform.cc45
-rw-r--r--src/node_platform.h14
-rw-r--r--src/node_worker.cc14
6 files changed, 59 insertions, 37 deletions
diff --git a/src/env.cc b/src/env.cc
index 5046aa0dd1..d791e41f92 100644
--- a/src/env.cc
+++ b/src/env.cc
@@ -84,8 +84,6 @@ IsolateData::IsolateData(Isolate* isolate,
uses_node_allocator_(allocator_ == node_allocator_),
platform_(platform) {
CHECK_NOT_NULL(allocator_);
- if (platform_ != nullptr)
- platform_->RegisterIsolate(isolate_, event_loop);
options_.reset(
new PerIsolateOptions(*(per_process::cli_options->per_isolate)));
@@ -137,12 +135,6 @@ IsolateData::IsolateData(Isolate* isolate,
#undef V
}
-IsolateData::~IsolateData() {
- if (platform_ != nullptr)
- platform_->UnregisterIsolate(isolate_);
-}
-
-
void InitThreadLocalOnce() {
CHECK_EQ(0, uv_key_create(&Environment::thread_local_env));
}
diff --git a/src/env.h b/src/env.h
index 15ca78b74b..e07e77aaa6 100644
--- a/src/env.h
+++ b/src/env.h
@@ -401,7 +401,6 @@ class IsolateData {
uv_loop_t* event_loop,
MultiIsolatePlatform* platform = nullptr,
ArrayBufferAllocator* node_allocator = nullptr);
- ~IsolateData();
inline uv_loop_t* event_loop() const;
inline MultiIsolatePlatform* platform() const;
inline std::shared_ptr<PerIsolateOptions> options();
diff --git a/src/node.h b/src/node.h
index 06b8bd0ff5..9ccab2e0f8 100644
--- a/src/node.h
+++ b/src/node.h
@@ -228,10 +228,22 @@ class NODE_EXTERN MultiIsolatePlatform : public v8::Platform {
virtual void DrainTasks(v8::Isolate* isolate) = 0;
virtual void CancelPendingDelayedTasks(v8::Isolate* isolate) = 0;
- // These will be called by the `IsolateData` creation/destruction functions.
+ // This needs to be called between the calls to `Isolate::Allocate()` and
+ // `Isolate::Initialize()`, so that initialization can already start
+ // using the platform.
+ // When using `NewIsolate()`, this is taken care of by that function.
+ // This function may only be called once per `Isolate`.
virtual void RegisterIsolate(v8::Isolate* isolate,
struct uv_loop_s* loop) = 0;
+ // This needs to be called right before calling `Isolate::Dispose()`.
+ // This function may only be called once per `Isolate`.
virtual void UnregisterIsolate(v8::Isolate* isolate) = 0;
+ // The platform should call the passed function once all state associated
+ // with the given isolate has been cleaned up. This can, but does not have to,
+ // happen asynchronously.
+ virtual void AddIsolateFinishedCallback(v8::Isolate* isolate,
+ void (*callback)(void*),
+ void* data) = 0;
};
// Creates a new isolate with Node.js-specific settings.
diff --git a/src/node_platform.cc b/src/node_platform.cc
index ba5ca794c0..bb64502919 100644
--- a/src/node_platform.cc
+++ b/src/node_platform.cc
@@ -261,6 +261,11 @@ PerIsolatePlatformData::~PerIsolatePlatformData() {
Shutdown();
}
+void PerIsolatePlatformData::AddShutdownCallback(void (*callback)(void*),
+ void* data) {
+ shutdown_callbacks_.emplace_back(ShutdownCallback { callback, data });
+}
+
void PerIsolatePlatformData::Shutdown() {
if (flush_tasks_ == nullptr)
return;
@@ -269,21 +274,19 @@ void PerIsolatePlatformData::Shutdown() {
CHECK_NULL(foreground_tasks_.Pop());
CancelPendingDelayedTasks();
+ ShutdownCbList* copy = new ShutdownCbList(std::move(shutdown_callbacks_));
+ flush_tasks_->data = copy;
uv_close(reinterpret_cast<uv_handle_t*>(flush_tasks_),
[](uv_handle_t* handle) {
+ std::unique_ptr<ShutdownCbList> callbacks(
+ static_cast<ShutdownCbList*>(handle->data));
+ for (const auto& callback : *callbacks)
+ callback.cb(callback.data);
delete reinterpret_cast<uv_async_t*>(handle);
});
flush_tasks_ = nullptr;
}
-void PerIsolatePlatformData::ref() {
- ref_count_++;
-}
-
-int PerIsolatePlatformData::unref() {
- return --ref_count_;
-}
-
NodePlatform::NodePlatform(int thread_pool_size,
TracingController* tracing_controller) {
if (tracing_controller) {
@@ -298,23 +301,29 @@ NodePlatform::NodePlatform(int thread_pool_size,
void NodePlatform::RegisterIsolate(Isolate* isolate, uv_loop_t* loop) {
Mutex::ScopedLock lock(per_isolate_mutex_);
std::shared_ptr<PerIsolatePlatformData> existing = per_isolate_[isolate];
- if (existing) {
- CHECK_EQ(loop, existing->event_loop());
- existing->ref();
- } else {
- per_isolate_[isolate] =
- std::make_shared<PerIsolatePlatformData>(isolate, loop);
- }
+ CHECK(!existing);
+ per_isolate_[isolate] =
+ std::make_shared<PerIsolatePlatformData>(isolate, loop);
}
void NodePlatform::UnregisterIsolate(Isolate* isolate) {
Mutex::ScopedLock lock(per_isolate_mutex_);
std::shared_ptr<PerIsolatePlatformData> existing = per_isolate_[isolate];
CHECK(existing);
- if (existing->unref() == 0) {
- existing->Shutdown();
- per_isolate_.erase(isolate);
+ existing->Shutdown();
+ per_isolate_.erase(isolate);
+}
+
+void NodePlatform::AddIsolateFinishedCallback(Isolate* isolate,
+ void (*cb)(void*), void* data) {
+ Mutex::ScopedLock lock(per_isolate_mutex_);
+ auto it = per_isolate_.find(isolate);
+ if (it == per_isolate_.end()) {
+ CHECK(it->second);
+ cb(data);
+ return;
}
+ it->second->AddShutdownCallback(cb, data);
}
void NodePlatform::Shutdown() {
diff --git a/src/node_platform.h b/src/node_platform.h
index f99f0f9b9b..55a1e80618 100644
--- a/src/node_platform.h
+++ b/src/node_platform.h
@@ -64,11 +64,9 @@ class PerIsolatePlatformData :
double delay_in_seconds) override;
bool IdleTasksEnabled() override { return false; }
+ void AddShutdownCallback(void (*callback)(void*), void* data);
void Shutdown();
- void ref();
- int unref();
-
// Returns true if work was dispatched or executed. New tasks that are
// posted during flushing of the queue are postponed until the next
// flushing.
@@ -84,7 +82,13 @@ class PerIsolatePlatformData :
static void RunForegroundTask(std::unique_ptr<v8::Task> task);
static void RunForegroundTask(uv_timer_t* timer);
- int ref_count_ = 1;
+ struct ShutdownCallback {
+ void (*cb)(void*);
+ void* data;
+ };
+ typedef std::vector<ShutdownCallback> ShutdownCbList;
+ ShutdownCbList shutdown_callbacks_;
+
uv_loop_t* const loop_;
uv_async_t* flush_tasks_ = nullptr;
TaskQueue<v8::Task> foreground_tasks_;
@@ -145,6 +149,8 @@ class NodePlatform : public MultiIsolatePlatform {
void RegisterIsolate(v8::Isolate* isolate, uv_loop_t* loop) override;
void UnregisterIsolate(v8::Isolate* isolate) override;
+ void AddIsolateFinishedCallback(v8::Isolate* isolate,
+ void (*callback)(void*), void* data) override;
std::shared_ptr<v8::TaskRunner> GetForegroundTaskRunner(
v8::Isolate* isolate) override;
diff --git a/src/node_worker.cc b/src/node_worker.cc
index 6f290c3e2a..42d407e654 100644
--- a/src/node_worker.cc
+++ b/src/node_worker.cc
@@ -188,16 +188,20 @@ class WorkerThreadData {
w_->platform_->CancelPendingDelayedTasks(isolate);
+ bool platform_finished = false;
+
isolate_data_.reset();
+
+ w_->platform_->AddIsolateFinishedCallback(isolate, [](void* data) {
+ *static_cast<bool*>(data) = true;
+ }, &platform_finished);
w_->platform_->UnregisterIsolate(isolate);
isolate->Dispose();
- // Need to run the loop twice more to close the platform's uv_async_t
- // TODO(addaleax): It would be better for the platform itself to provide
- // some kind of notification when it has fully cleaned up.
- uv_run(&loop_, UV_RUN_ONCE);
- uv_run(&loop_, UV_RUN_ONCE);
+ // Wait until the platform has cleaned up all relevant resources.
+ while (!platform_finished)
+ uv_run(&loop_, UV_RUN_ONCE);
CheckedUvLoopClose(&loop_);
}