#include "node_platform.h"
#include "node_internals.h"
#include "env.h"
#include "env-inl.h"
#include "util.h"
#include
namespace node {
using v8::HandleScope;
using v8::Isolate;
using v8::Local;
using v8::Object;
using v8::Platform;
using v8::Task;
using v8::TracingController;
static void BackgroundRunner(void* data) {
TaskQueue* background_tasks = static_cast*>(data);
while (std::unique_ptr task = background_tasks->BlockingPop()) {
task->Run();
background_tasks->NotifyOfCompletion();
}
}
BackgroundTaskRunner::BackgroundTaskRunner(int thread_pool_size) {
for (int i = 0; i < thread_pool_size; i++) {
std::unique_ptr t { new uv_thread_t() };
if (uv_thread_create(t.get(), BackgroundRunner, &background_tasks_) != 0)
break;
threads_.push_back(std::move(t));
}
}
void BackgroundTaskRunner::PostTask(std::unique_ptr task) {
background_tasks_.Push(std::move(task));
}
void BackgroundTaskRunner::PostIdleTask(std::unique_ptr<:idletask> task) {
UNREACHABLE();
}
void BackgroundTaskRunner::PostDelayedTask(std::unique_ptr<:task> task,
double delay_in_seconds) {
UNREACHABLE();
}
void BackgroundTaskRunner::BlockingDrain() {
background_tasks_.BlockingDrain();
}
void BackgroundTaskRunner::Shutdown() {
background_tasks_.Stop();
for (size_t i = 0; i < threads_.size(); i++) {
CHECK_EQ(0, uv_thread_join(threads_[i].get()));
}
}
size_t BackgroundTaskRunner::NumberOfAvailableBackgroundThreads() const {
return threads_.size();
}
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(this);
uv_unref(reinterpret_cast(flush_tasks_));
}
void PerIsolatePlatformData::FlushTasks(uv_async_t* handle) {
auto platform_data = static_cast(handle->data);
platform_data->FlushForegroundTasksInternal();
}
void PerIsolatePlatformData::PostIdleTask(std::unique_ptr<:idletask> task) {
UNREACHABLE();
}
void PerIsolatePlatformData::PostTask(std::unique_ptr task) {
foreground_tasks_.Push(std::move(task));
uv_async_send(flush_tasks_);
}
void PerIsolatePlatformData::PostDelayedTask(
std::unique_ptr task, double delay_in_seconds) {
std::unique_ptr delayed(new DelayedTask());
delayed->task = std::move(task);
delayed->platform_data = shared_from_this();
delayed->timeout = delay_in_seconds;
foreground_delayed_tasks_.Push(std::move(delayed));
uv_async_send(flush_tasks_);
}
PerIsolatePlatformData::~PerIsolatePlatformData() {
FlushForegroundTasksInternal();
CancelPendingDelayedTasks();
uv_close(reinterpret_cast(flush_tasks_),
[](uv_handle_t* handle) {
delete reinterpret_cast(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 {
TracingController* controller = new TracingController();
tracing_controller_.reset(controller);
}
background_task_runner_ =
std::make_shared(thread_pool_size);
}
void NodePlatform::RegisterIsolate(IsolateData* isolate_data, uv_loop_t* loop) {
Isolate* isolate = isolate_data->isolate();
Mutex::ScopedLock lock(per_isolate_mutex_);
std::shared_ptr existing = per_isolate_[isolate];
if (existing) {
existing->ref();
} else {
per_isolate_[isolate] =
std::make_shared(isolate, loop);
}
}
void NodePlatform::UnregisterIsolate(IsolateData* isolate_data) {
Isolate* isolate = isolate_data->isolate();
Mutex::ScopedLock lock(per_isolate_mutex_);
std::shared_ptr existing = per_isolate_[isolate];
CHECK(existing);
if (existing->unref() == 0) {
per_isolate_.erase(isolate);
}
}
void NodePlatform::Shutdown() {
background_task_runner_->Shutdown();
{
Mutex::ScopedLock lock(per_isolate_mutex_);
per_isolate_.clear();
}
}
size_t NodePlatform::NumberOfAvailableBackgroundThreads() {
return background_task_runner_->NumberOfAvailableBackgroundThreads();
}
void PerIsolatePlatformData::RunForegroundTask(std::unique_ptr task) {
Isolate* isolate = Isolate::GetCurrent();
HandleScope scope(isolate);
Environment* env = Environment::GetCurrent(isolate);
InternalCallbackScope cb_scope(env, Local