Skip to content

Instantly share code, notes, and snippets.

@deepal
Created October 15, 2019 21:31
Show Gist options
  • Select an option

  • Save deepal/6f2e2529aabe24018e5a38e822c7916b to your computer and use it in GitHub Desktop.

Select an option

Save deepal/6f2e2529aabe24018e5a38e822c7916b to your computer and use it in GitHub Desktop.
Worker::Run() Run worker thread
void Worker::Run() {
std::string name = "WorkerThread ";
name += std::to_string(thread_id_);
TRACE_EVENT_METADATA1(
"__metadata", "thread_name", "name",
TRACE_STR_COPY(name.c_str()));
CHECK_NOT_NULL(platform_);
std::cout << "node_worker.cc[Worker::Run()] Creating WorkerThreadData for worker with id " << thread_id_ << "\n";
Debug(this, "Creating isolate for worker with id %llu", thread_id_);
// Construction of WorkerThreadData instance will create a new isolate and will assign it as
// the isolate of the worker which was passed as the constructor argument
WorkerThreadData data(this);
Debug(this, "Starting worker with id %llu", thread_id_);
{
Locker locker(isolate_);
Isolate::Scope isolate_scope(isolate_);
SealHandleScope outer_seal(isolate_);
#if NODE_USE_V8_PLATFORM && HAVE_INSPECTOR
bool inspector_started = false;
#endif
DeleteFnPtr<Environment, FreeEnvironment> env_;
OnScopeLeave cleanup_env([&]() {
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();
{
Mutex::ScopedLock lock(mutex_);
stopped_ = true;
this->env_ = nullptr;
}
env_->thread_stopper()->set_stopped(true);
env_->stop_sub_worker_contexts();
env_->RunCleanup();
RunAtExit(env_.get());
#if NODE_USE_V8_PLATFORM && HAVE_INSPECTOR
if (inspector_started)
WaitForWorkerInspectorToStop(env_.get());
#endif
// 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_);
}
});
if (is_stopped()) return;
{
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.
std::cout << "node_worker.cc[Worker::Run()] Resetting worker environment\n";
env_.reset(new Environment(data.isolate_data_.get(),
context,
std::move(argv_),
std::move(exec_argv_),
Environment::kNoFlags,
thread_id_));
CHECK_NOT_NULL(env_);
env_->set_env_vars(std::move(env_vars_));
env_->set_abort_on_uncaught_exception(false);
env_->set_worker_context(this);
std::cout<<"node_worker.cc[Worker::Run()] Initializing libuv for thread " << thread_id_ << "\n";
env_->InitializeLibuv(start_profiler_idle_notifier_);
}
{
Mutex::ScopedLock lock(mutex_);
if (stopped_) return;
this->env_ = env_.get();
}
Debug(this, "Created Environment for worker with id %llu", thread_id_);
if (is_stopped()) return;
{
env_->InitializeDiagnostics();
#if NODE_USE_V8_PLATFORM && HAVE_INSPECTOR
env_->InitializeInspector(inspector_parent_handle_.release());
inspector_started = true;
#endif
HandleScope handle_scope(isolate_);
AsyncCallbackScope callback_scope(env_.get());
env_->async_hooks()->push_async_ids(1, 0);
if (!env_->RunBootstrapping().IsEmpty()) {
CreateEnvMessagePort(env_.get());
if (is_stopped()) return;
std::cout<<"node_worker.cc[Worker::Run()] Created message port for worker " << thread_id_ << "\n";
Debug(this, "Created message port for worker %llu", thread_id_);
std::cout<<"node_worker.cc[Worker::Run()] Running script internal/main/worker_thread \n";
USE(StartExecution(env_.get(), "internal/main/worker_thread"));
}
env_->async_hooks()->pop_async_id(1);
Debug(this, "Loaded environment for worker %llu", thread_id_);
}
if (is_stopped()) return;
{
SealHandleScope seal(isolate_);
bool more;
env_->performance_state()->Mark(
node::performance::NODE_PERFORMANCE_MILESTONE_LOOP_START);
std::cout<<"node_worker.cc[Worker::Run()] Starting event loop on worker thread " << thread_id_ << "\n";
do {
if (is_stopped()) break;
uv_run(&data.loop_, UV_RUN_DEFAULT);
if (is_stopped()) break;
platform_->DrainTasks(isolate_);
more = uv_loop_alive(&data.loop_);
if (more && !is_stopped()) continue;
std::cout<<"node_worker.cc[Worker::Run()] Emitting 'beforeExit' on worker thread " << thread_id_ << "\n";
EmitBeforeExit(env_.get());
// Emit `beforeExit` if the loop became alive either after emitting
// event, or after running some callbacks.
more = uv_loop_alive(&data.loop_);
} while (more == true && !is_stopped());
env_->performance_state()->Mark(
node::performance::NODE_PERFORMANCE_MILESTONE_LOOP_EXIT);
}
}
{
int exit_code;
bool stopped = is_stopped();
if (!stopped)
std::cout<<"node_worker.cc[Worker::Run()] Emitting 'exit' on worker thread " << thread_id_ << "\n";
exit_code = EmitExit(env_.get());
Mutex::ScopedLock lock(mutex_);
if (exit_code_ == 0 && !stopped)
exit_code_ = exit_code;
#if HAVE_INSPECTOR
profiler::EndStartedProfilers(env_.get());
#endif
std::cout << "node_worker.cc[Worker::Run()] Exiting thread for worker " << thread_id_ << " with exit code " << exit_code_ << " \n";
Debug(this, "Exiting thread for worker %llu with exit code %d",
thread_id_, exit_code_);
}
}
Debug(this, "Worker %llu thread stops", thread_id_);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment