summaryrefslogtreecommitdiff
path: root/src/node_platform.cc
diff options
context:
space:
mode:
authorAnna Henningsen <anna@addaleax.net>2017-09-14 13:05:48 +0200
committerAnna Henningsen <anna@addaleax.net>2017-11-12 14:01:54 +0100
commitc7ad729072186594521f5d1033ebb101bfdd36f7 (patch)
tree6c426b5f31eaf70fef48e41f7b87859cee16f0e5 /src/node_platform.cc
parenta645d45dd500f5b73efb1e940ffafadcf61f3628 (diff)
downloadandroid-node-v8-c7ad729072186594521f5d1033ebb101bfdd36f7.tar.gz
android-node-v8-c7ad729072186594521f5d1033ebb101bfdd36f7.tar.bz2
android-node-v8-c7ad729072186594521f5d1033ebb101bfdd36f7.zip
src: prepare v8 platform for multi-isolate support
This splits the task queue used for asynchronous tasks scheduled by V8 in per-isolate queues, so that multiple threads can be supported. Original-PR-URL: https://github.com/ayojs/ayo/pull/89 Original-Reviewed-By: Timothy Gu <timothygu99@gmail.com> PR-URL: https://github.com/nodejs/node/pull/16700 Reviewed-By: James M Snell <jasnell@gmail.com>
Diffstat (limited to 'src/node_platform.cc')
-rw-r--r--src/node_platform.cc120
1 files changed, 94 insertions, 26 deletions
diff --git a/src/node_platform.cc b/src/node_platform.cc
index 56b13b8437..ec2fca6c41 100644
--- a/src/node_platform.cc
+++ b/src/node_platform.cc
@@ -1,6 +1,8 @@
#include "node_platform.h"
#include "node_internals.h"
+#include "env.h"
+#include "env-inl.h"
#include "util.h"
namespace node {
@@ -13,11 +15,6 @@ using v8::Platform;
using v8::Task;
using v8::TracingController;
-static void FlushTasks(uv_async_t* handle) {
- NodePlatform* platform = static_cast<NodePlatform*>(handle->data);
- platform->FlushForegroundTasksInternal();
-}
-
static void BackgroundRunner(void* data) {
TaskQueue<Task>* background_tasks = static_cast<TaskQueue<Task>*>(data);
while (Task* task = background_tasks->BlockingPop()) {
@@ -27,12 +24,51 @@ static void BackgroundRunner(void* data) {
}
}
-NodePlatform::NodePlatform(int thread_pool_size, uv_loop_t* loop,
- TracingController* tracing_controller)
- : loop_(loop) {
- CHECK_EQ(0, uv_async_init(loop, &flush_tasks_, FlushTasks));
- flush_tasks_.data = static_cast<void*>(this);
- uv_unref(reinterpret_cast<uv_handle_t*>(&flush_tasks_));
+PerIsolatePlatformData::PerIsolatePlatformData(
+ v8::Isolate* isolate, uv_loop_t* loop)
+ : isolate_(isolate), loop_(loop) {
+ flush_tasks_ = new uv_async_t();
+ CHECK_EQ(0, uv_async_init(loop, flush_tasks_, FlushTasks));
+ flush_tasks_->data = static_cast<void*>(this);
+ uv_unref(reinterpret_cast<uv_handle_t*>(flush_tasks_));
+}
+
+void PerIsolatePlatformData::FlushTasks(uv_async_t* handle) {
+ auto platform_data = static_cast<PerIsolatePlatformData*>(handle->data);
+ platform_data->FlushForegroundTasksInternal();
+}
+
+void PerIsolatePlatformData::CallOnForegroundThread(Task* task) {
+ foreground_tasks_.Push(task);
+ uv_async_send(flush_tasks_);
+}
+
+void PerIsolatePlatformData::CallDelayedOnForegroundThread(
+ Task* task, double delay_in_seconds) {
+ auto pair = new std::pair<Task*, double>(task, delay_in_seconds);
+ foreground_delayed_tasks_.Push(pair);
+ uv_async_send(flush_tasks_);
+}
+
+PerIsolatePlatformData::~PerIsolatePlatformData() {
+ FlushForegroundTasksInternal();
+
+ uv_close(reinterpret_cast<uv_handle_t*>(flush_tasks_),
+ [](uv_handle_t* handle) {
+ delete reinterpret_cast<uv_async_t*>(handle);
+ });
+}
+
+void PerIsolatePlatformData::ref() {
+ ref_count_++;
+}
+
+int PerIsolatePlatformData::unref() {
+ return --ref_count_;
+}
+
+NodePlatform::NodePlatform(int thread_pool_size,
+ TracingController* tracing_controller) {
if (tracing_controller) {
tracing_controller_.reset(tracing_controller);
} else {
@@ -49,18 +85,35 @@ NodePlatform::NodePlatform(int thread_pool_size, uv_loop_t* loop,
}
}
+void NodePlatform::RegisterIsolate(IsolateData* isolate_data, uv_loop_t* loop) {
+ Isolate* isolate = isolate_data->isolate();
+ Mutex::ScopedLock lock(per_isolate_mutex_);
+ PerIsolatePlatformData* existing = per_isolate_[isolate];
+ if (existing != nullptr)
+ existing->ref();
+ else
+ per_isolate_[isolate] = new PerIsolatePlatformData(isolate, loop);
+}
+
+void NodePlatform::UnregisterIsolate(IsolateData* isolate_data) {
+ Isolate* isolate = isolate_data->isolate();
+ Mutex::ScopedLock lock(per_isolate_mutex_);
+ PerIsolatePlatformData* existing = per_isolate_[isolate];
+ CHECK_NE(existing, nullptr);
+ if (existing->unref() == 0) {
+ delete existing;
+ per_isolate_.erase(isolate);
+ }
+}
+
void NodePlatform::Shutdown() {
background_tasks_.Stop();
for (size_t i = 0; i < threads_.size(); i++) {
CHECK_EQ(0, uv_thread_join(threads_[i].get()));
}
- // uv_run cannot be called from the time before the beforeExit callback
- // runs until the program exits unless the event loop has any referenced
- // handles after beforeExit terminates. This prevents unrefed timers
- // that happen to terminate during shutdown from being run unsafely.
- // Since uv_run cannot be called, this handle will never be fully cleaned
- // up.
- uv_close(reinterpret_cast<uv_handle_t*>(&flush_tasks_), nullptr);
+ Mutex::ScopedLock lock(per_isolate_mutex_);
+ for (const auto& pair : per_isolate_)
+ delete pair.second;
}
size_t NodePlatform::NumberOfAvailableBackgroundThreads() {
@@ -85,13 +138,19 @@ static void RunForegroundTask(uv_timer_t* handle) {
});
}
-void NodePlatform::DrainBackgroundTasks() {
+void NodePlatform::DrainBackgroundTasks(Isolate* isolate) {
+ PerIsolatePlatformData* per_isolate = ForIsolate(isolate);
+
do {
+ // Right now, there is no way to drain only background tasks associated with
+ // a specific isolate, so this sometimes does more work than necessary.
+ // In the long run, that functionality is probably going to be available
+ // anyway, though.
background_tasks_.BlockingDrain();
- } while (FlushForegroundTasksInternal());
+ } while (per_isolate->FlushForegroundTasksInternal());
}
-bool NodePlatform::FlushForegroundTasksInternal() {
+bool PerIsolatePlatformData::FlushForegroundTasksInternal() {
bool did_work = false;
while (auto delayed = foreground_delayed_tasks_.Pop()) {
did_work = true;
@@ -118,17 +177,26 @@ void NodePlatform::CallOnBackgroundThread(Task* task,
background_tasks_.Push(task);
}
+PerIsolatePlatformData* NodePlatform::ForIsolate(Isolate* isolate) {
+ Mutex::ScopedLock lock(per_isolate_mutex_);
+ PerIsolatePlatformData* data = per_isolate_[isolate];
+ CHECK_NE(data, nullptr);
+ return data;
+}
+
void NodePlatform::CallOnForegroundThread(Isolate* isolate, Task* task) {
- foreground_tasks_.Push(task);
- uv_async_send(&flush_tasks_);
+ ForIsolate(isolate)->CallOnForegroundThread(task);
}
void NodePlatform::CallDelayedOnForegroundThread(Isolate* isolate,
Task* task,
double delay_in_seconds) {
- auto pair = new std::pair<Task*, double>(task, delay_in_seconds);
- foreground_delayed_tasks_.Push(pair);
- uv_async_send(&flush_tasks_);
+ ForIsolate(isolate)->CallDelayedOnForegroundThread(task,
+ delay_in_seconds);
+}
+
+void NodePlatform::FlushForegroundTasks(v8::Isolate* isolate) {
+ ForIsolate(isolate)->FlushForegroundTasksInternal();
}
bool NodePlatform::IdleTasksEnabled(Isolate* isolate) { return false; }