Skip to content
This repository has been archived by the owner on Mar 4, 2020. It is now read-only.

Commit

Permalink
backport: src: use modern v8::Platform worker threads APIs
Browse files Browse the repository at this point in the history
Precursor to removing deprecated APIs on the v8 side @
https://chromium-review.googlesource.com/c/v8/v8/+/1045310

PR-URL: nodejs/node#21079
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Yang Guo <yangguo@chromium.org>
(cherry-picked from 0f3c2c6)
  • Loading branch information
Gabriel Charette authored and codebytere committed Oct 2, 2018
1 parent 86c6016 commit 59a15b1
Show file tree
Hide file tree
Showing 5 changed files with 57 additions and 59 deletions.
2 changes: 1 addition & 1 deletion src/node.cc
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,7 @@ static struct {
}

void DrainVMTasks(Isolate* isolate) {
platform_->DrainBackgroundTasks(isolate);
platform_->DrainTasks(isolate);
}

void CancelVMTasks(Isolate* isolate) {
Expand Down
2 changes: 1 addition & 1 deletion src/node.h
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ class NODE_EXTERN MultiIsolatePlatform : public v8::Platform {
// posted during flushing of the queue are postponed until the next
// flushing.
virtual bool FlushForegroundTasks(v8::Isolate* isolate) = 0;
virtual void DrainBackgroundTasks(v8::Isolate* isolate) = 0;
virtual void DrainTasks(v8::Isolate* isolate) = 0;
virtual void CancelPendingDelayedTasks(v8::Isolate* isolate) = 0;

// These will be called by the `IsolateData` creation/destruction functions.
Expand Down
78 changes: 39 additions & 39 deletions src/node_platform.cc
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,21 @@ using v8::Platform;
using v8::Task;
using v8::TracingController;

static void BackgroundRunner(void* data) {
namespace {

static void WorkerThreadMain(void* data) {
TRACE_EVENT_METADATA1("__metadata", "thread_name", "name",
"BackgroundTaskRunner");
TaskQueue<Task> *background_tasks = static_cast<TaskQueue<Task> *>(data);
while (std::unique_ptr<Task> task = background_tasks->BlockingPop()) {
TaskQueue<Task>* pending_worker_tasks = static_cast<TaskQueue<Task>*>(data);
while (std::unique_ptr<Task> task = pending_worker_tasks->BlockingPop()) {
task->Run();
background_tasks->NotifyOfCompletion();
pending_worker_tasks->NotifyOfCompletion();
}
}

class BackgroundTaskRunner::DelayedTaskScheduler {
} // namespace

class WorkerThreadsTaskRunner::DelayedTaskScheduler {
public:
explicit DelayedTaskScheduler(TaskQueue<Task>* tasks)
: pending_worker_tasks_(tasks) {}
Expand Down Expand Up @@ -144,44 +148,42 @@ class BackgroundTaskRunner::DelayedTaskScheduler {
std::unordered_set<uv_timer_t*> timers_;
};

BackgroundTaskRunner::BackgroundTaskRunner(int thread_pool_size) {
WorkerThreadsTaskRunner::WorkerThreadsTaskRunner(int thread_pool_size) {
delayed_task_scheduler_.reset(
new DelayedTaskScheduler(&background_tasks_));
new DelayedTaskScheduler(&pending_worker_tasks_));
threads_.push_back(delayed_task_scheduler_->Start());
for (int i = 0; i < thread_pool_size; i++) {
std::unique_ptr<uv_thread_t> t { new uv_thread_t() };
if (uv_thread_create(t.get(), BackgroundRunner, &background_tasks_) != 0)
if (uv_thread_create(t.get(), WorkerThreadMain,
&pending_worker_tasks_) != 0) {
break;
}
threads_.push_back(std::move(t));
}
}

void BackgroundTaskRunner::PostTask(std::unique_ptr<Task> task) {
background_tasks_.Push(std::move(task));
}

void BackgroundTaskRunner::PostIdleTask(std::unique_ptr<v8::IdleTask> task) {
UNREACHABLE();
void WorkerThreadsTaskRunner::PostTask(std::unique_ptr<Task> task) {
pending_worker_tasks_.Push(std::move(task));
}

void BackgroundTaskRunner::PostDelayedTask(std::unique_ptr<v8::Task> task,
void WorkerThreadsTaskRunner::PostDelayedTask(std::unique_ptr<v8::Task> task,
double delay_in_seconds) {
delayed_task_scheduler_->PostDelayedTask(std::move(task), delay_in_seconds);
}

void BackgroundTaskRunner::BlockingDrain() {
background_tasks_.BlockingDrain();
void WorkerThreadsTaskRunner::BlockingDrain() {
pending_worker_tasks_.BlockingDrain();
}

void BackgroundTaskRunner::Shutdown() {
background_tasks_.Stop();
void WorkerThreadsTaskRunner::Shutdown() {
pending_worker_tasks_.Stop();
delayed_task_scheduler_->Stop();
for (size_t i = 0; i < threads_.size(); i++) {
CHECK_EQ(0, uv_thread_join(threads_[i].get()));
}
}

size_t BackgroundTaskRunner::NumberOfAvailableBackgroundThreads() const {
int WorkerThreadsTaskRunner::NumberOfWorkerThreads() const {
return threads_.size();
}

Expand Down Expand Up @@ -254,8 +256,8 @@ NodePlatform::NodePlatform(int thread_pool_size,
TracingController* controller = new TracingController();
tracing_controller_.reset(controller);
}
background_task_runner_ =
std::make_shared<BackgroundTaskRunner>(thread_pool_size);
worker_thread_task_runner_ =
std::make_shared<WorkerThreadsTaskRunner>(thread_pool_size);
}

void NodePlatform::RegisterIsolate(IsolateData* isolate_data, uv_loop_t* loop) {
Expand Down Expand Up @@ -283,16 +285,16 @@ void NodePlatform::UnregisterIsolate(IsolateData* isolate_data) {
}

void NodePlatform::Shutdown() {
background_task_runner_->Shutdown();
worker_thread_task_runner_->Shutdown();

{
Mutex::ScopedLock lock(per_isolate_mutex_);
per_isolate_.clear();
}
}

size_t NodePlatform::NumberOfAvailableBackgroundThreads() {
return background_task_runner_->NumberOfAvailableBackgroundThreads();
int NodePlatform::NumberOfWorkerThreads() {
return worker_thread_task_runner_->NumberOfWorkerThreads();
}

void PerIsolatePlatformData::RunForegroundTask(std::unique_ptr<Task> task) {
Expand Down Expand Up @@ -324,15 +326,12 @@ void PerIsolatePlatformData::CancelPendingDelayedTasks() {
scheduled_delayed_tasks_.clear();
}

void NodePlatform::DrainBackgroundTasks(Isolate* isolate) {
void NodePlatform::DrainTasks(Isolate* isolate) {
std::shared_ptr<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_task_runner_->BlockingDrain();
// Worker tasks aren't associated with an Isolate.
worker_thread_task_runner_->BlockingDrain();
} while (per_isolate->FlushForegroundTasksInternal());
}

Expand Down Expand Up @@ -372,11 +371,17 @@ bool PerIsolatePlatformData::FlushForegroundTasksInternal() {
return did_work;
}

void NodePlatform::CallOnBackgroundThread(Task* task,
ExpectedRuntime expected_runtime) {
background_task_runner_->PostTask(std::unique_ptr<Task>(task));
void NodePlatform::CallOnWorkerThread(std::unique_ptr<v8::Task> task) {
worker_thread_task_runner_->PostTask(std::move(task));
}

void NodePlatform::CallDelayedOnWorkerThread(std::unique_ptr<v8::Task> task,
double delay_in_seconds) {
worker_thread_task_runner_->PostDelayedTask(std::move(task),
delay_in_seconds);
}


std::shared_ptr<PerIsolatePlatformData>
NodePlatform::ForIsolate(Isolate* isolate) {
Mutex::ScopedLock lock(per_isolate_mutex_);
Expand Down Expand Up @@ -406,11 +411,6 @@ void NodePlatform::CancelPendingDelayedTasks(v8::Isolate* isolate) {

bool NodePlatform::IdleTasksEnabled(Isolate* isolate) { return false; }

std::shared_ptr<v8::TaskRunner>
NodePlatform::GetBackgroundTaskRunner(Isolate* isolate) {
return background_task_runner_;
}

std::shared_ptr<v8::TaskRunner>
NodePlatform::GetForegroundTaskRunner(Isolate* isolate) {
return ForIsolate(isolate);
Expand Down
30 changes: 14 additions & 16 deletions src/node_platform.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,23 +95,22 @@ class PerIsolatePlatformData :
std::vector<DelayedTaskPointer> scheduled_delayed_tasks_;
};

// This acts as the single background task runner for all Isolates.
class BackgroundTaskRunner : public v8::TaskRunner {
// This acts as the single worker thread task runner for all Isolates.
class WorkerThreadsTaskRunner {
public:
explicit BackgroundTaskRunner(int thread_pool_size);
explicit WorkerThreadsTaskRunner(int thread_pool_size);

void PostTask(std::unique_ptr<v8::Task> task) override;
void PostIdleTask(std::unique_ptr<v8::IdleTask> task) override;
void PostTask(std::unique_ptr<v8::Task> task);
void PostDelayedTask(std::unique_ptr<v8::Task> task,
double delay_in_seconds) override;
bool IdleTasksEnabled() override { return false; };
double delay_in_seconds);

void BlockingDrain();
void Shutdown();

size_t NumberOfAvailableBackgroundThreads() const;
int NumberOfWorkerThreads() const;

private:
TaskQueue<v8::Task> background_tasks_;
TaskQueue<v8::Task> pending_worker_tasks_;

class DelayedTaskScheduler;
std::unique_ptr<DelayedTaskScheduler> delayed_task_scheduler_;
Expand All @@ -124,14 +123,15 @@ class NodePlatform : public MultiIsolatePlatform {
NodePlatform(int thread_pool_size, v8::TracingController* tracing_controller);
virtual ~NodePlatform() {}

void DrainBackgroundTasks(v8::Isolate* isolate) override;
void DrainTasks(v8::Isolate* isolate) override;
void CancelPendingDelayedTasks(v8::Isolate* isolate) override;
void Shutdown();

// v8::Platform implementation.
size_t NumberOfAvailableBackgroundThreads() override;
void CallOnBackgroundThread(v8::Task* task,
ExpectedRuntime expected_runtime) override;
int NumberOfWorkerThreads() override;
void CallOnWorkerThread(std::unique_ptr<v8::Task> task) override;
void CallDelayedOnWorkerThread(std::unique_ptr<v8::Task> task,
double delay_in_seconds) override;
void CallOnForegroundThread(v8::Isolate* isolate, v8::Task* task) override;
void CallDelayedOnForegroundThread(v8::Isolate* isolate, v8::Task* task,
double delay_in_seconds) override;
Expand All @@ -144,8 +144,6 @@ class NodePlatform : public MultiIsolatePlatform {
void RegisterIsolate(IsolateData* isolate_data, uv_loop_t* loop) override;
void UnregisterIsolate(IsolateData* isolate_data) override;

std::shared_ptr<v8::TaskRunner> GetBackgroundTaskRunner(
v8::Isolate* isolate) override;
std::shared_ptr<v8::TaskRunner> GetForegroundTaskRunner(
v8::Isolate* isolate) override;

Expand All @@ -157,7 +155,7 @@ class NodePlatform : public MultiIsolatePlatform {
std::shared_ptr<PerIsolatePlatformData>> per_isolate_;

std::unique_ptr<v8::TracingController> tracing_controller_;
std::shared_ptr<BackgroundTaskRunner> background_task_runner_;
std::shared_ptr<WorkerThreadsTaskRunner> worker_thread_task_runner_;
};

} // namespace node
Expand Down
4 changes: 2 additions & 2 deletions src/node_worker.cc
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ void Worker::Run() {
uv_run(&loop_, UV_RUN_DEFAULT);
if (is_stopped()) break;

platform->DrainBackgroundTasks(isolate_);
platform->DrainTasks(isolate_);

more = uv_loop_alive(&loop_);
if (more && !is_stopped())
Expand Down Expand Up @@ -227,7 +227,7 @@ void Worker::Run() {
// This call needs to be made while the `Environment` is still alive
// because we assume that it is available for async tracking in the
// NodePlatform implementation.
platform->DrainBackgroundTasks(isolate_);
platform->DrainTasks(isolate_);
}

env_.reset();
Expand Down

0 comments on commit 59a15b1

Please sign in to comment.