worker: set up child Isolate inside Worker thread
Refs: https://github.com/nodejs/node/issues/24016 PR-URL: https://github.com/nodejs/node/pull/26011 Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com> Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Gireesh Punathil <gpunathi@in.ibm.com> Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com>
This commit is contained in:
parent
58ba8bfc46
commit
5bc6e493c0
@ -885,12 +885,14 @@ bool Agent::IsActive() {
|
|||||||
return io_ != nullptr || client_->IsActive();
|
return io_ != nullptr || client_->IsActive();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Agent::AddWorkerInspector(int thread_id,
|
void Agent::SetParentHandle(
|
||||||
const std::string& url,
|
std::unique_ptr<ParentInspectorHandle> parent_handle) {
|
||||||
Agent* agent) {
|
parent_handle_ = std::move(parent_handle);
|
||||||
CHECK_NOT_NULL(client_);
|
}
|
||||||
agent->parent_handle_ =
|
|
||||||
client_->getWorkerManager()->NewParentHandle(thread_id, url);
|
std::unique_ptr<ParentInspectorHandle> Agent::GetParentHandle(
|
||||||
|
int thread_id, const std::string& url) {
|
||||||
|
return client_->getWorkerManager()->NewParentHandle(thread_id, url);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Agent::WaitForConnect() {
|
void Agent::WaitForConnect() {
|
||||||
|
@ -85,7 +85,9 @@ class Agent {
|
|||||||
void EnableAsyncHook();
|
void EnableAsyncHook();
|
||||||
void DisableAsyncHook();
|
void DisableAsyncHook();
|
||||||
|
|
||||||
void AddWorkerInspector(int thread_id, const std::string& url, Agent* agent);
|
void SetParentHandle(std::unique_ptr<ParentInspectorHandle> parent_handle);
|
||||||
|
std::unique_ptr<ParentInspectorHandle> GetParentHandle(
|
||||||
|
int thread_id, const std::string& url);
|
||||||
|
|
||||||
// Called to create inspector sessions that can be used from the main thread.
|
// Called to create inspector sessions that can be used from the main thread.
|
||||||
// The inspector responds by using the delegate to send messages back.
|
// The inspector responds by using the delegate to send messages back.
|
||||||
|
@ -8,6 +8,10 @@
|
|||||||
#include "async_wrap.h"
|
#include "async_wrap.h"
|
||||||
#include "async_wrap-inl.h"
|
#include "async_wrap-inl.h"
|
||||||
|
|
||||||
|
#if NODE_USE_V8_PLATFORM && HAVE_INSPECTOR
|
||||||
|
#include "inspector/worker_inspector.h" // ParentInspectorHandle
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@ -35,34 +39,21 @@ namespace worker {
|
|||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
#if NODE_USE_V8_PLATFORM && HAVE_INSPECTOR
|
#if NODE_USE_V8_PLATFORM && HAVE_INSPECTOR
|
||||||
void StartWorkerInspector(Environment* child, const std::string& url) {
|
void StartWorkerInspector(
|
||||||
|
Environment* child,
|
||||||
|
std::unique_ptr<inspector::ParentInspectorHandle> parent_handle,
|
||||||
|
const std::string& url) {
|
||||||
|
child->inspector_agent()->SetParentHandle(std::move(parent_handle));
|
||||||
child->inspector_agent()->Start(url,
|
child->inspector_agent()->Start(url,
|
||||||
child->options()->debug_options(),
|
child->options()->debug_options(),
|
||||||
child->inspector_host_port(),
|
child->inspector_host_port(),
|
||||||
false);
|
false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AddWorkerInspector(Environment* parent,
|
|
||||||
Environment* child,
|
|
||||||
int id,
|
|
||||||
const std::string& url) {
|
|
||||||
parent->inspector_agent()->AddWorkerInspector(id, url,
|
|
||||||
child->inspector_agent());
|
|
||||||
}
|
|
||||||
|
|
||||||
void WaitForWorkerInspectorToStop(Environment* child) {
|
void WaitForWorkerInspectorToStop(Environment* child) {
|
||||||
child->inspector_agent()->WaitForDisconnect();
|
child->inspector_agent()->WaitForDisconnect();
|
||||||
child->inspector_agent()->Stop();
|
child->inspector_agent()->Stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
|
||||||
// No-ops
|
|
||||||
void StartWorkerInspector(Environment* child, const std::string& url) {}
|
|
||||||
void AddWorkerInspector(Environment* parent,
|
|
||||||
Environment* child,
|
|
||||||
int id,
|
|
||||||
const std::string& url) {}
|
|
||||||
void WaitForWorkerInspectorToStop(Environment* child) {}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
@ -71,9 +62,13 @@ Worker::Worker(Environment* env,
|
|||||||
Local<Object> wrap,
|
Local<Object> wrap,
|
||||||
const std::string& url,
|
const std::string& url,
|
||||||
std::shared_ptr<PerIsolateOptions> per_isolate_opts)
|
std::shared_ptr<PerIsolateOptions> per_isolate_opts)
|
||||||
: AsyncWrap(env, wrap, AsyncWrap::PROVIDER_WORKER), url_(url),
|
: AsyncWrap(env, wrap, AsyncWrap::PROVIDER_WORKER),
|
||||||
|
url_(url),
|
||||||
|
per_isolate_opts_(per_isolate_opts),
|
||||||
|
platform_(env->isolate_data()->platform()),
|
||||||
|
profiler_idle_notifier_started_(env->profiler_idle_notifier_started()),
|
||||||
thread_id_(Environment::AllocateThreadId()) {
|
thread_id_(Environment::AllocateThreadId()) {
|
||||||
Debug(this, "Creating new worker instance at %p", static_cast<void*>(this));
|
Debug(this, "Creating new worker instance with thread id %llu", thread_id_);
|
||||||
|
|
||||||
// Set up everything that needs to be set up in the parent environment.
|
// Set up everything that needs to be set up in the parent environment.
|
||||||
parent_port_ = MessagePort::New(env, env->context());
|
parent_port_ = MessagePort::New(env, env->context());
|
||||||
@ -89,57 +84,17 @@ Worker::Worker(Environment* env,
|
|||||||
env->message_port_string(),
|
env->message_port_string(),
|
||||||
parent_port_->object()).FromJust();
|
parent_port_->object()).FromJust();
|
||||||
|
|
||||||
array_buffer_allocator_.reset(CreateArrayBufferAllocator());
|
object()->Set(env->context(),
|
||||||
|
env->thread_id_string(),
|
||||||
CHECK_EQ(uv_loop_init(&loop_), 0);
|
Number::New(env->isolate(), static_cast<double>(thread_id_)))
|
||||||
isolate_ = NewIsolate(array_buffer_allocator_.get(), &loop_);
|
|
||||||
CHECK_NOT_NULL(isolate_);
|
|
||||||
|
|
||||||
{
|
|
||||||
// Enter an environment capable of executing code in the child Isolate
|
|
||||||
// (and only in it).
|
|
||||||
Locker locker(isolate_);
|
|
||||||
Isolate::Scope isolate_scope(isolate_);
|
|
||||||
HandleScope handle_scope(isolate_);
|
|
||||||
|
|
||||||
isolate_data_.reset(CreateIsolateData(isolate_,
|
|
||||||
&loop_,
|
|
||||||
env->isolate_data()->platform(),
|
|
||||||
array_buffer_allocator_.get()));
|
|
||||||
if (per_isolate_opts != nullptr) {
|
|
||||||
isolate_data_->set_options(per_isolate_opts);
|
|
||||||
}
|
|
||||||
CHECK(isolate_data_);
|
|
||||||
|
|
||||||
Local<Context> context = NewContext(isolate_);
|
|
||||||
Context::Scope context_scope(context);
|
|
||||||
|
|
||||||
// TODO(addaleax): Use CreateEnvironment(), or generally another public API.
|
|
||||||
env_.reset(new Environment(
|
|
||||||
isolate_data_.get(), context, Flags::kNoFlags, thread_id_));
|
|
||||||
CHECK_NOT_NULL(env_);
|
|
||||||
env_->set_abort_on_uncaught_exception(false);
|
|
||||||
env_->set_worker_context(this);
|
|
||||||
|
|
||||||
env_->Start(env->profiler_idle_notifier_started());
|
|
||||||
env_->ProcessCliArgs(std::vector<std::string>{},
|
|
||||||
std::vector<std::string>{});
|
|
||||||
// Done while on the parent thread
|
|
||||||
AddWorkerInspector(env, env_.get(), thread_id_, url_);
|
|
||||||
}
|
|
||||||
|
|
||||||
// The new isolate won't be bothered on this thread again.
|
|
||||||
isolate_->DiscardThreadSpecificMetadata();
|
|
||||||
|
|
||||||
wrap->Set(env->context(),
|
|
||||||
env->thread_id_string(),
|
|
||||||
Number::New(env->isolate(), static_cast<double>(thread_id_)))
|
|
||||||
.FromJust();
|
.FromJust();
|
||||||
|
|
||||||
Debug(this,
|
#if NODE_USE_V8_PLATFORM && HAVE_INSPECTOR
|
||||||
"Set up worker at %p with id %llu",
|
inspector_parent_handle_ =
|
||||||
static_cast<void*>(this),
|
env->inspector_agent()->GetParentHandle(thread_id_, url);
|
||||||
thread_id_);
|
#endif
|
||||||
|
|
||||||
|
Debug(this, "Preparation for worker %llu finished", thread_id_);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Worker::is_stopped() const {
|
bool Worker::is_stopped() const {
|
||||||
@ -147,14 +102,79 @@ bool Worker::is_stopped() const {
|
|||||||
return stopped_;
|
return stopped_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This class contains data that is only relevant to the child thread itself,
|
||||||
|
// and only while it is running.
|
||||||
|
// (Eventually, the Environment instance should probably also be moved here.)
|
||||||
|
class WorkerThreadData {
|
||||||
|
public:
|
||||||
|
explicit WorkerThreadData(Worker* w)
|
||||||
|
: w_(w),
|
||||||
|
array_buffer_allocator_(CreateArrayBufferAllocator()) {
|
||||||
|
CHECK_EQ(uv_loop_init(&loop_), 0);
|
||||||
|
|
||||||
|
Isolate* isolate = NewIsolate(array_buffer_allocator_.get(), &loop_);
|
||||||
|
CHECK_NOT_NULL(isolate);
|
||||||
|
|
||||||
|
{
|
||||||
|
Locker locker(isolate);
|
||||||
|
Isolate::Scope isolate_scope(isolate);
|
||||||
|
HandleScope handle_scope(isolate);
|
||||||
|
isolate_data_.reset(CreateIsolateData(isolate,
|
||||||
|
&loop_,
|
||||||
|
w_->platform_,
|
||||||
|
array_buffer_allocator_.get()));
|
||||||
|
CHECK(isolate_data_);
|
||||||
|
if (w_->per_isolate_opts_)
|
||||||
|
isolate_data_->set_options(std::move(w_->per_isolate_opts_));
|
||||||
|
}
|
||||||
|
|
||||||
|
Mutex::ScopedLock lock(w_->mutex_);
|
||||||
|
w_->isolate_ = isolate;
|
||||||
|
}
|
||||||
|
|
||||||
|
~WorkerThreadData() {
|
||||||
|
Debug(w_, "Worker %llu dispose isolate", w_->thread_id_);
|
||||||
|
Isolate* isolate;
|
||||||
|
{
|
||||||
|
Mutex::ScopedLock lock(w_->mutex_);
|
||||||
|
isolate = w_->isolate_;
|
||||||
|
w_->isolate_ = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
w_->platform_->CancelPendingDelayedTasks(isolate);
|
||||||
|
|
||||||
|
isolate_data_.reset();
|
||||||
|
w_->platform_->UnregisterIsolate(isolate);
|
||||||
|
|
||||||
|
isolate->Dispose();
|
||||||
|
|
||||||
|
// Need to run the loop one more time to close the platform's uv_async_t
|
||||||
|
uv_run(&loop_, UV_RUN_ONCE);
|
||||||
|
|
||||||
|
CheckedUvLoopClose(&loop_);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Worker* const w_;
|
||||||
|
uv_loop_t loop_;
|
||||||
|
DeleteFnPtr<ArrayBufferAllocator, FreeArrayBufferAllocator>
|
||||||
|
array_buffer_allocator_;
|
||||||
|
DeleteFnPtr<IsolateData, FreeIsolateData> isolate_data_;
|
||||||
|
|
||||||
|
friend class Worker;
|
||||||
|
};
|
||||||
|
|
||||||
void Worker::Run() {
|
void Worker::Run() {
|
||||||
std::string name = "WorkerThread ";
|
std::string name = "WorkerThread ";
|
||||||
name += std::to_string(thread_id_);
|
name += std::to_string(thread_id_);
|
||||||
TRACE_EVENT_METADATA1(
|
TRACE_EVENT_METADATA1(
|
||||||
"__metadata", "thread_name", "name",
|
"__metadata", "thread_name", "name",
|
||||||
TRACE_STR_COPY(name.c_str()));
|
TRACE_STR_COPY(name.c_str()));
|
||||||
MultiIsolatePlatform* platform = isolate_data_->platform();
|
CHECK_NOT_NULL(platform_);
|
||||||
CHECK_NOT_NULL(platform);
|
|
||||||
|
Debug(this, "Creating isolate for worker with id %llu", thread_id_);
|
||||||
|
|
||||||
|
WorkerThreadData data(this);
|
||||||
|
|
||||||
Debug(this, "Starting worker with id %llu", thread_id_);
|
Debug(this, "Starting worker with id %llu", thread_id_);
|
||||||
{
|
{
|
||||||
@ -163,10 +183,73 @@ void Worker::Run() {
|
|||||||
SealHandleScope outer_seal(isolate_);
|
SealHandleScope outer_seal(isolate_);
|
||||||
bool inspector_started = false;
|
bool inspector_started = false;
|
||||||
|
|
||||||
{
|
DeleteFnPtr<Environment, FreeEnvironment> env_;
|
||||||
Context::Scope context_scope(env_->context());
|
OnScopeLeave cleanup_env([&]() {
|
||||||
HandleScope handle_scope(isolate_);
|
if (!env_) return;
|
||||||
|
env_->set_can_call_into_js(false);
|
||||||
|
Isolate::DisallowJavascriptExecutionScope disallow_js(isolate_,
|
||||||
|
Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE);
|
||||||
|
|
||||||
|
// Grab the parent-to-child channel and render is unusable.
|
||||||
|
MessagePort* child_port;
|
||||||
|
{
|
||||||
|
Mutex::ScopedLock lock(mutex_);
|
||||||
|
child_port = child_port_;
|
||||||
|
child_port_ = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
Context::Scope context_scope(env_->context());
|
||||||
|
if (child_port != nullptr)
|
||||||
|
child_port->Close();
|
||||||
|
env_->stop_sub_worker_contexts();
|
||||||
|
env_->RunCleanup();
|
||||||
|
RunAtExit(env_.get());
|
||||||
|
#if NODE_USE_V8_PLATFORM && HAVE_INSPECTOR
|
||||||
|
if (inspector_started)
|
||||||
|
WaitForWorkerInspectorToStop(env_.get());
|
||||||
|
#endif
|
||||||
|
|
||||||
|
{
|
||||||
|
Mutex::ScopedLock stopped_lock(stopped_mutex_);
|
||||||
|
stopped_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
env_->RunCleanup();
|
||||||
|
|
||||||
|
// 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_->DrainTasks(isolate_);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
{
|
||||||
|
HandleScope handle_scope(isolate_);
|
||||||
|
Local<Context> context = NewContext(isolate_);
|
||||||
|
if (is_stopped()) return;
|
||||||
|
|
||||||
|
CHECK(!context.IsEmpty());
|
||||||
|
Context::Scope context_scope(context);
|
||||||
|
{
|
||||||
|
// TODO(addaleax): Use CreateEnvironment(), or generally another
|
||||||
|
// public API.
|
||||||
|
env_.reset(new Environment(data.isolate_data_.get(),
|
||||||
|
context,
|
||||||
|
Environment::kNoFlags,
|
||||||
|
thread_id_));
|
||||||
|
CHECK_NOT_NULL(env_);
|
||||||
|
env_->set_abort_on_uncaught_exception(false);
|
||||||
|
env_->set_worker_context(this);
|
||||||
|
|
||||||
|
env_->Start(profiler_idle_notifier_started_);
|
||||||
|
env_->ProcessCliArgs(std::vector<std::string>{},
|
||||||
|
std::vector<std::string>{});
|
||||||
|
}
|
||||||
|
|
||||||
|
Debug(this, "Created Environment for worker with id %llu", thread_id_);
|
||||||
|
|
||||||
|
if (is_stopped()) return;
|
||||||
{
|
{
|
||||||
HandleScope handle_scope(isolate_);
|
HandleScope handle_scope(isolate_);
|
||||||
Mutex::ScopedLock lock(mutex_);
|
Mutex::ScopedLock lock(mutex_);
|
||||||
@ -182,8 +265,13 @@ void Worker::Run() {
|
|||||||
Debug(this, "Created message port for worker %llu", thread_id_);
|
Debug(this, "Created message port for worker %llu", thread_id_);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!is_stopped()) {
|
if (is_stopped()) return;
|
||||||
StartWorkerInspector(env_.get(), url_);
|
{
|
||||||
|
#if NODE_USE_V8_PLATFORM && HAVE_INSPECTOR
|
||||||
|
StartWorkerInspector(env_.get(),
|
||||||
|
std::move(inspector_parent_handle_),
|
||||||
|
url_);
|
||||||
|
#endif
|
||||||
inspector_started = true;
|
inspector_started = true;
|
||||||
|
|
||||||
HandleScope handle_scope(isolate_);
|
HandleScope handle_scope(isolate_);
|
||||||
@ -198,6 +286,7 @@ void Worker::Run() {
|
|||||||
Debug(this, "Loaded environment for worker %llu", thread_id_);
|
Debug(this, "Loaded environment for worker %llu", thread_id_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (is_stopped()) return;
|
||||||
{
|
{
|
||||||
SealHandleScope seal(isolate_);
|
SealHandleScope seal(isolate_);
|
||||||
bool more;
|
bool more;
|
||||||
@ -205,12 +294,12 @@ void Worker::Run() {
|
|||||||
node::performance::NODE_PERFORMANCE_MILESTONE_LOOP_START);
|
node::performance::NODE_PERFORMANCE_MILESTONE_LOOP_START);
|
||||||
do {
|
do {
|
||||||
if (is_stopped()) break;
|
if (is_stopped()) break;
|
||||||
uv_run(&loop_, UV_RUN_DEFAULT);
|
uv_run(&data.loop_, UV_RUN_DEFAULT);
|
||||||
if (is_stopped()) break;
|
if (is_stopped()) break;
|
||||||
|
|
||||||
platform->DrainTasks(isolate_);
|
platform_->DrainTasks(isolate_);
|
||||||
|
|
||||||
more = uv_loop_alive(&loop_);
|
more = uv_loop_alive(&data.loop_);
|
||||||
if (more && !is_stopped())
|
if (more && !is_stopped())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -218,7 +307,7 @@ void Worker::Run() {
|
|||||||
|
|
||||||
// Emit `beforeExit` if the loop became alive either after emitting
|
// Emit `beforeExit` if the loop became alive either after emitting
|
||||||
// event, or after running some callbacks.
|
// event, or after running some callbacks.
|
||||||
more = uv_loop_alive(&loop_);
|
more = uv_loop_alive(&data.loop_);
|
||||||
} while (more == true);
|
} while (more == true);
|
||||||
env_->performance_state()->Mark(
|
env_->performance_state()->Mark(
|
||||||
node::performance::NODE_PERFORMANCE_MILESTONE_LOOP_EXIT);
|
node::performance::NODE_PERFORMANCE_MILESTONE_LOOP_EXIT);
|
||||||
@ -237,79 +326,11 @@ void Worker::Run() {
|
|||||||
Debug(this, "Exiting thread for worker %llu with exit code %d",
|
Debug(this, "Exiting thread for worker %llu with exit code %d",
|
||||||
thread_id_, exit_code_);
|
thread_id_, exit_code_);
|
||||||
}
|
}
|
||||||
|
|
||||||
env_->set_can_call_into_js(false);
|
|
||||||
Isolate::DisallowJavascriptExecutionScope disallow_js(isolate_,
|
|
||||||
Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE);
|
|
||||||
|
|
||||||
// Grab the parent-to-child channel and render is unusable.
|
|
||||||
MessagePort* child_port;
|
|
||||||
{
|
|
||||||
Mutex::ScopedLock lock(mutex_);
|
|
||||||
child_port = child_port_;
|
|
||||||
child_port_ = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
Context::Scope context_scope(env_->context());
|
|
||||||
child_port->Close();
|
|
||||||
env_->stop_sub_worker_contexts();
|
|
||||||
env_->RunCleanup();
|
|
||||||
RunAtExit(env_.get());
|
|
||||||
if (inspector_started)
|
|
||||||
WaitForWorkerInspectorToStop(env_.get());
|
|
||||||
|
|
||||||
{
|
|
||||||
Mutex::ScopedLock stopped_lock(stopped_mutex_);
|
|
||||||
stopped_ = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
env_->RunCleanup();
|
|
||||||
|
|
||||||
// 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->DrainTasks(isolate_);
|
|
||||||
}
|
|
||||||
|
|
||||||
env_.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
DisposeIsolate();
|
|
||||||
|
|
||||||
{
|
|
||||||
Mutex::ScopedLock lock(mutex_);
|
|
||||||
CHECK(thread_exit_async_);
|
|
||||||
scheduled_on_thread_stopped_ = true;
|
|
||||||
uv_async_send(thread_exit_async_.get());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Debug(this, "Worker %llu thread stops", thread_id_);
|
Debug(this, "Worker %llu thread stops", thread_id_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Worker::DisposeIsolate() {
|
|
||||||
if (env_) {
|
|
||||||
CHECK_NOT_NULL(isolate_);
|
|
||||||
Locker locker(isolate_);
|
|
||||||
Isolate::Scope isolate_scope(isolate_);
|
|
||||||
env_.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isolate_ == nullptr)
|
|
||||||
return;
|
|
||||||
|
|
||||||
Debug(this, "Worker %llu dispose isolate", thread_id_);
|
|
||||||
CHECK(isolate_data_);
|
|
||||||
MultiIsolatePlatform* platform = isolate_data_->platform();
|
|
||||||
platform->CancelPendingDelayedTasks(isolate_);
|
|
||||||
|
|
||||||
isolate_data_.reset();
|
|
||||||
platform->UnregisterIsolate(isolate_);
|
|
||||||
|
|
||||||
isolate_->Dispose();
|
|
||||||
isolate_ = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Worker::JoinThread() {
|
void Worker::JoinThread() {
|
||||||
if (thread_joined_)
|
if (thread_joined_)
|
||||||
return;
|
return;
|
||||||
@ -340,7 +361,6 @@ void Worker::OnThreadStopped() {
|
|||||||
CHECK(stopped_);
|
CHECK(stopped_);
|
||||||
}
|
}
|
||||||
|
|
||||||
CHECK_NULL(child_port_);
|
|
||||||
parent_port_ = nullptr;
|
parent_port_ = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -370,16 +390,9 @@ Worker::~Worker() {
|
|||||||
|
|
||||||
CHECK(stopped_);
|
CHECK(stopped_);
|
||||||
CHECK(thread_joined_);
|
CHECK(thread_joined_);
|
||||||
CHECK_NULL(child_port_);
|
|
||||||
|
|
||||||
// This has most likely already happened within the worker thread -- this
|
// This has most likely already happened within the worker thread -- this
|
||||||
// is just in case Worker creation failed early.
|
// is just in case Worker creation failed early.
|
||||||
DisposeIsolate();
|
|
||||||
|
|
||||||
// Need to run the loop one more time to close the platform's uv_async_t
|
|
||||||
uv_run(&loop_, UV_RUN_ONCE);
|
|
||||||
|
|
||||||
CheckedUvLoopClose(&loop_);
|
|
||||||
|
|
||||||
Debug(this, "Worker %llu destroyed", thread_id_);
|
Debug(this, "Worker %llu destroyed", thread_id_);
|
||||||
}
|
}
|
||||||
@ -476,7 +489,13 @@ void Worker::StartThread(const FunctionCallbackInfo<Value>& args) {
|
|||||||
}), 0);
|
}), 0);
|
||||||
|
|
||||||
CHECK_EQ(uv_thread_create(&w->tid_, [](void* arg) {
|
CHECK_EQ(uv_thread_create(&w->tid_, [](void* arg) {
|
||||||
static_cast<Worker*>(arg)->Run();
|
Worker* w = static_cast<Worker*>(arg);
|
||||||
|
w->Run();
|
||||||
|
|
||||||
|
Mutex::ScopedLock lock(w->mutex_);
|
||||||
|
CHECK(w->thread_exit_async_);
|
||||||
|
w->scheduled_on_thread_stopped_ = true;
|
||||||
|
uv_async_send(w->thread_exit_async_.get());
|
||||||
}, static_cast<void*>(w)), 0);
|
}, static_cast<void*>(w)), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -510,12 +529,12 @@ void Worker::Exit(int code) {
|
|||||||
Debug(this, "Worker %llu called Exit(%d)", thread_id_, code);
|
Debug(this, "Worker %llu called Exit(%d)", thread_id_, code);
|
||||||
|
|
||||||
if (!stopped_) {
|
if (!stopped_) {
|
||||||
CHECK_NOT_NULL(env_);
|
|
||||||
stopped_ = true;
|
stopped_ = true;
|
||||||
exit_code_ = code;
|
exit_code_ = code;
|
||||||
if (child_port_ != nullptr)
|
if (child_port_ != nullptr)
|
||||||
child_port_->StopEventLoop();
|
child_port_->StopEventLoop();
|
||||||
isolate_->TerminateExecution();
|
if (isolate_ != nullptr)
|
||||||
|
isolate_->TerminateExecution();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,6 +9,8 @@
|
|||||||
namespace node {
|
namespace node {
|
||||||
namespace worker {
|
namespace worker {
|
||||||
|
|
||||||
|
class WorkerThreadData;
|
||||||
|
|
||||||
// A worker thread, as represented in its parent thread.
|
// A worker thread, as represented in its parent thread.
|
||||||
class Worker : public AsyncWrap {
|
class Worker : public AsyncWrap {
|
||||||
public:
|
public:
|
||||||
@ -49,17 +51,19 @@ class Worker : public AsyncWrap {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
void OnThreadStopped();
|
void OnThreadStopped();
|
||||||
void DisposeIsolate();
|
|
||||||
|
|
||||||
uv_loop_t loop_;
|
|
||||||
DeleteFnPtr<IsolateData, FreeIsolateData> isolate_data_;
|
|
||||||
DeleteFnPtr<Environment, FreeEnvironment> env_;
|
|
||||||
const std::string url_;
|
const std::string url_;
|
||||||
|
|
||||||
|
std::shared_ptr<PerIsolateOptions> per_isolate_opts_;
|
||||||
|
MultiIsolatePlatform* platform_;
|
||||||
v8::Isolate* isolate_ = nullptr;
|
v8::Isolate* isolate_ = nullptr;
|
||||||
DeleteFnPtr<ArrayBufferAllocator, FreeArrayBufferAllocator>
|
bool profiler_idle_notifier_started_;
|
||||||
array_buffer_allocator_;
|
|
||||||
uv_thread_t tid_;
|
uv_thread_t tid_;
|
||||||
|
|
||||||
|
#if NODE_USE_V8_PLATFORM && HAVE_INSPECTOR
|
||||||
|
std::unique_ptr<inspector::ParentInspectorHandle> inspector_parent_handle_;
|
||||||
|
#endif
|
||||||
|
|
||||||
// This mutex protects access to all variables listed below it.
|
// This mutex protects access to all variables listed below it.
|
||||||
mutable Mutex mutex_;
|
mutable Mutex mutex_;
|
||||||
|
|
||||||
@ -79,12 +83,14 @@ class Worker : public AsyncWrap {
|
|||||||
|
|
||||||
std::unique_ptr<MessagePortData> child_port_data_;
|
std::unique_ptr<MessagePortData> child_port_data_;
|
||||||
|
|
||||||
// The child port is always kept alive by the child Environment's persistent
|
// The child port is kept alive by the child Environment's persistent
|
||||||
// handle to it.
|
// handle to it, as long as that child Environment exists.
|
||||||
MessagePort* child_port_ = nullptr;
|
MessagePort* child_port_ = nullptr;
|
||||||
// This is always kept alive because the JS object associated with the Worker
|
// This is always kept alive because the JS object associated with the Worker
|
||||||
// instance refers to it via its [kPort] property.
|
// instance refers to it via its [kPort] property.
|
||||||
MessagePort* parent_port_ = nullptr;
|
MessagePort* parent_port_ = nullptr;
|
||||||
|
|
||||||
|
friend class WorkerThreadData;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace worker
|
} // namespace worker
|
||||||
|
Loading…
x
Reference in New Issue
Block a user