11cb0ef41Sopenharmony_ci#include "node_worker.h" 21cb0ef41Sopenharmony_ci#include "debug_utils-inl.h" 31cb0ef41Sopenharmony_ci#include "histogram-inl.h" 41cb0ef41Sopenharmony_ci#include "memory_tracker-inl.h" 51cb0ef41Sopenharmony_ci#include "node_errors.h" 61cb0ef41Sopenharmony_ci#include "node_external_reference.h" 71cb0ef41Sopenharmony_ci#include "node_buffer.h" 81cb0ef41Sopenharmony_ci#include "node_options-inl.h" 91cb0ef41Sopenharmony_ci#include "node_perf.h" 101cb0ef41Sopenharmony_ci#include "node_snapshot_builder.h" 111cb0ef41Sopenharmony_ci#include "util-inl.h" 121cb0ef41Sopenharmony_ci#include "async_wrap-inl.h" 131cb0ef41Sopenharmony_ci 141cb0ef41Sopenharmony_ci#include <memory> 151cb0ef41Sopenharmony_ci#include <string> 161cb0ef41Sopenharmony_ci#include <vector> 171cb0ef41Sopenharmony_ci 181cb0ef41Sopenharmony_ciusing node::kAllowedInEnvvar; 191cb0ef41Sopenharmony_ciusing node::kDisallowedInEnvvar; 201cb0ef41Sopenharmony_ciusing v8::Array; 211cb0ef41Sopenharmony_ciusing v8::ArrayBuffer; 221cb0ef41Sopenharmony_ciusing v8::Boolean; 231cb0ef41Sopenharmony_ciusing v8::Context; 241cb0ef41Sopenharmony_ciusing v8::Float64Array; 251cb0ef41Sopenharmony_ciusing v8::FunctionCallbackInfo; 261cb0ef41Sopenharmony_ciusing v8::FunctionTemplate; 271cb0ef41Sopenharmony_ciusing v8::HandleScope; 281cb0ef41Sopenharmony_ciusing v8::Integer; 291cb0ef41Sopenharmony_ciusing v8::Isolate; 301cb0ef41Sopenharmony_ciusing v8::Local; 311cb0ef41Sopenharmony_ciusing v8::Locker; 321cb0ef41Sopenharmony_ciusing v8::Maybe; 331cb0ef41Sopenharmony_ciusing v8::MaybeLocal; 341cb0ef41Sopenharmony_ciusing v8::Null; 351cb0ef41Sopenharmony_ciusing v8::Number; 361cb0ef41Sopenharmony_ciusing v8::Object; 371cb0ef41Sopenharmony_ciusing v8::ResourceConstraints; 381cb0ef41Sopenharmony_ciusing v8::SealHandleScope; 391cb0ef41Sopenharmony_ciusing v8::String; 401cb0ef41Sopenharmony_ciusing v8::TryCatch; 411cb0ef41Sopenharmony_ciusing v8::Value; 421cb0ef41Sopenharmony_ci 431cb0ef41Sopenharmony_cinamespace node { 441cb0ef41Sopenharmony_cinamespace worker { 451cb0ef41Sopenharmony_ci 461cb0ef41Sopenharmony_ciconstexpr double kMB = 1024 * 1024; 471cb0ef41Sopenharmony_ci 481cb0ef41Sopenharmony_ciWorker::Worker(Environment* env, 491cb0ef41Sopenharmony_ci Local<Object> wrap, 501cb0ef41Sopenharmony_ci const std::string& url, 511cb0ef41Sopenharmony_ci const std::string& name, 521cb0ef41Sopenharmony_ci std::shared_ptr<PerIsolateOptions> per_isolate_opts, 531cb0ef41Sopenharmony_ci std::vector<std::string>&& exec_argv, 541cb0ef41Sopenharmony_ci std::shared_ptr<KVStore> env_vars, 551cb0ef41Sopenharmony_ci const SnapshotData* snapshot_data) 561cb0ef41Sopenharmony_ci : AsyncWrap(env, wrap, AsyncWrap::PROVIDER_WORKER), 571cb0ef41Sopenharmony_ci per_isolate_opts_(per_isolate_opts), 581cb0ef41Sopenharmony_ci exec_argv_(exec_argv), 591cb0ef41Sopenharmony_ci platform_(env->isolate_data()->platform()), 601cb0ef41Sopenharmony_ci thread_id_(AllocateEnvironmentThreadId()), 611cb0ef41Sopenharmony_ci name_(name), 621cb0ef41Sopenharmony_ci env_vars_(env_vars), 631cb0ef41Sopenharmony_ci snapshot_data_(snapshot_data) { 641cb0ef41Sopenharmony_ci Debug(this, "Creating new worker instance with thread id %llu", 651cb0ef41Sopenharmony_ci thread_id_.id); 661cb0ef41Sopenharmony_ci 671cb0ef41Sopenharmony_ci // Set up everything that needs to be set up in the parent environment. 681cb0ef41Sopenharmony_ci MessagePort* parent_port = MessagePort::New(env, env->context()); 691cb0ef41Sopenharmony_ci if (parent_port == nullptr) { 701cb0ef41Sopenharmony_ci // This can happen e.g. because execution is terminating. 711cb0ef41Sopenharmony_ci return; 721cb0ef41Sopenharmony_ci } 731cb0ef41Sopenharmony_ci 741cb0ef41Sopenharmony_ci child_port_data_ = std::make_unique<MessagePortData>(nullptr); 751cb0ef41Sopenharmony_ci MessagePort::Entangle(parent_port, child_port_data_.get()); 761cb0ef41Sopenharmony_ci 771cb0ef41Sopenharmony_ci object() 781cb0ef41Sopenharmony_ci ->Set(env->context(), env->message_port_string(), parent_port->object()) 791cb0ef41Sopenharmony_ci .Check(); 801cb0ef41Sopenharmony_ci 811cb0ef41Sopenharmony_ci object()->Set(env->context(), 821cb0ef41Sopenharmony_ci env->thread_id_string(), 831cb0ef41Sopenharmony_ci Number::New(env->isolate(), static_cast<double>(thread_id_.id))) 841cb0ef41Sopenharmony_ci .Check(); 851cb0ef41Sopenharmony_ci 861cb0ef41Sopenharmony_ci inspector_parent_handle_ = 871cb0ef41Sopenharmony_ci GetInspectorParentHandle(env, thread_id_, url.c_str(), name.c_str()); 881cb0ef41Sopenharmony_ci 891cb0ef41Sopenharmony_ci argv_ = std::vector<std::string>{env->argv()[0]}; 901cb0ef41Sopenharmony_ci // Mark this Worker object as weak until we actually start the thread. 911cb0ef41Sopenharmony_ci MakeWeak(); 921cb0ef41Sopenharmony_ci 931cb0ef41Sopenharmony_ci Debug(this, "Preparation for worker %llu finished", thread_id_.id); 941cb0ef41Sopenharmony_ci} 951cb0ef41Sopenharmony_ci 961cb0ef41Sopenharmony_cibool Worker::is_stopped() const { 971cb0ef41Sopenharmony_ci Mutex::ScopedLock lock(mutex_); 981cb0ef41Sopenharmony_ci if (env_ != nullptr) 991cb0ef41Sopenharmony_ci return env_->is_stopping(); 1001cb0ef41Sopenharmony_ci return stopped_; 1011cb0ef41Sopenharmony_ci} 1021cb0ef41Sopenharmony_ci 1031cb0ef41Sopenharmony_civoid Worker::UpdateResourceConstraints(ResourceConstraints* constraints) { 1041cb0ef41Sopenharmony_ci constraints->set_stack_limit(reinterpret_cast<uint32_t*>(stack_base_)); 1051cb0ef41Sopenharmony_ci 1061cb0ef41Sopenharmony_ci if (resource_limits_[kMaxYoungGenerationSizeMb] > 0) { 1071cb0ef41Sopenharmony_ci constraints->set_max_young_generation_size_in_bytes( 1081cb0ef41Sopenharmony_ci static_cast<size_t>(resource_limits_[kMaxYoungGenerationSizeMb] * kMB)); 1091cb0ef41Sopenharmony_ci } else { 1101cb0ef41Sopenharmony_ci resource_limits_[kMaxYoungGenerationSizeMb] = 1111cb0ef41Sopenharmony_ci constraints->max_young_generation_size_in_bytes() / kMB; 1121cb0ef41Sopenharmony_ci } 1131cb0ef41Sopenharmony_ci 1141cb0ef41Sopenharmony_ci if (resource_limits_[kMaxOldGenerationSizeMb] > 0) { 1151cb0ef41Sopenharmony_ci constraints->set_max_old_generation_size_in_bytes( 1161cb0ef41Sopenharmony_ci static_cast<size_t>(resource_limits_[kMaxOldGenerationSizeMb] * kMB)); 1171cb0ef41Sopenharmony_ci } else { 1181cb0ef41Sopenharmony_ci resource_limits_[kMaxOldGenerationSizeMb] = 1191cb0ef41Sopenharmony_ci constraints->max_old_generation_size_in_bytes() / kMB; 1201cb0ef41Sopenharmony_ci } 1211cb0ef41Sopenharmony_ci 1221cb0ef41Sopenharmony_ci if (resource_limits_[kCodeRangeSizeMb] > 0) { 1231cb0ef41Sopenharmony_ci constraints->set_code_range_size_in_bytes( 1241cb0ef41Sopenharmony_ci static_cast<size_t>(resource_limits_[kCodeRangeSizeMb] * kMB)); 1251cb0ef41Sopenharmony_ci } else { 1261cb0ef41Sopenharmony_ci resource_limits_[kCodeRangeSizeMb] = 1271cb0ef41Sopenharmony_ci constraints->code_range_size_in_bytes() / kMB; 1281cb0ef41Sopenharmony_ci } 1291cb0ef41Sopenharmony_ci} 1301cb0ef41Sopenharmony_ci 1311cb0ef41Sopenharmony_ci// This class contains data that is only relevant to the child thread itself, 1321cb0ef41Sopenharmony_ci// and only while it is running. 1331cb0ef41Sopenharmony_ci// (Eventually, the Environment instance should probably also be moved here.) 1341cb0ef41Sopenharmony_ciclass WorkerThreadData { 1351cb0ef41Sopenharmony_ci public: 1361cb0ef41Sopenharmony_ci explicit WorkerThreadData(Worker* w) 1371cb0ef41Sopenharmony_ci : w_(w) { 1381cb0ef41Sopenharmony_ci int ret = uv_loop_init(&loop_); 1391cb0ef41Sopenharmony_ci if (ret != 0) { 1401cb0ef41Sopenharmony_ci char err_buf[128]; 1411cb0ef41Sopenharmony_ci uv_err_name_r(ret, err_buf, sizeof(err_buf)); 1421cb0ef41Sopenharmony_ci w->Exit(1, "ERR_WORKER_INIT_FAILED", err_buf); 1431cb0ef41Sopenharmony_ci return; 1441cb0ef41Sopenharmony_ci } 1451cb0ef41Sopenharmony_ci loop_init_failed_ = false; 1461cb0ef41Sopenharmony_ci uv_loop_configure(&loop_, UV_METRICS_IDLE_TIME); 1471cb0ef41Sopenharmony_ci 1481cb0ef41Sopenharmony_ci std::shared_ptr<ArrayBufferAllocator> allocator = 1491cb0ef41Sopenharmony_ci ArrayBufferAllocator::Create(); 1501cb0ef41Sopenharmony_ci Isolate::CreateParams params; 1511cb0ef41Sopenharmony_ci SetIsolateCreateParamsForNode(¶ms); 1521cb0ef41Sopenharmony_ci w->UpdateResourceConstraints(¶ms.constraints); 1531cb0ef41Sopenharmony_ci params.array_buffer_allocator_shared = allocator; 1541cb0ef41Sopenharmony_ci Isolate* isolate = 1551cb0ef41Sopenharmony_ci NewIsolate(¶ms, &loop_, w->platform_, w->snapshot_data()); 1561cb0ef41Sopenharmony_ci if (isolate == nullptr) { 1571cb0ef41Sopenharmony_ci w->Exit(1, "ERR_WORKER_INIT_FAILED", "Failed to create new Isolate"); 1581cb0ef41Sopenharmony_ci return; 1591cb0ef41Sopenharmony_ci } 1601cb0ef41Sopenharmony_ci 1611cb0ef41Sopenharmony_ci SetIsolateUpForNode(isolate); 1621cb0ef41Sopenharmony_ci 1631cb0ef41Sopenharmony_ci // Be sure it's called before Environment::InitializeDiagnostics() 1641cb0ef41Sopenharmony_ci // so that this callback stays when the callback of 1651cb0ef41Sopenharmony_ci // --heapsnapshot-near-heap-limit gets is popped. 1661cb0ef41Sopenharmony_ci isolate->AddNearHeapLimitCallback(Worker::NearHeapLimit, w); 1671cb0ef41Sopenharmony_ci 1681cb0ef41Sopenharmony_ci { 1691cb0ef41Sopenharmony_ci Locker locker(isolate); 1701cb0ef41Sopenharmony_ci Isolate::Scope isolate_scope(isolate); 1711cb0ef41Sopenharmony_ci // V8 computes its stack limit the first time a `Locker` is used based on 1721cb0ef41Sopenharmony_ci // --stack-size. Reset it to the correct value. 1731cb0ef41Sopenharmony_ci isolate->SetStackLimit(w->stack_base_); 1741cb0ef41Sopenharmony_ci 1751cb0ef41Sopenharmony_ci HandleScope handle_scope(isolate); 1761cb0ef41Sopenharmony_ci isolate_data_.reset(CreateIsolateData(isolate, 1771cb0ef41Sopenharmony_ci &loop_, 1781cb0ef41Sopenharmony_ci w_->platform_, 1791cb0ef41Sopenharmony_ci allocator.get())); 1801cb0ef41Sopenharmony_ci CHECK(isolate_data_); 1811cb0ef41Sopenharmony_ci if (w_->per_isolate_opts_) 1821cb0ef41Sopenharmony_ci isolate_data_->set_options(std::move(w_->per_isolate_opts_)); 1831cb0ef41Sopenharmony_ci isolate_data_->set_worker_context(w_); 1841cb0ef41Sopenharmony_ci isolate_data_->max_young_gen_size = 1851cb0ef41Sopenharmony_ci params.constraints.max_young_generation_size_in_bytes(); 1861cb0ef41Sopenharmony_ci } 1871cb0ef41Sopenharmony_ci 1881cb0ef41Sopenharmony_ci Mutex::ScopedLock lock(w_->mutex_); 1891cb0ef41Sopenharmony_ci w_->isolate_ = isolate; 1901cb0ef41Sopenharmony_ci } 1911cb0ef41Sopenharmony_ci 1921cb0ef41Sopenharmony_ci ~WorkerThreadData() { 1931cb0ef41Sopenharmony_ci Debug(w_, "Worker %llu dispose isolate", w_->thread_id_.id); 1941cb0ef41Sopenharmony_ci Isolate* isolate; 1951cb0ef41Sopenharmony_ci { 1961cb0ef41Sopenharmony_ci Mutex::ScopedLock lock(w_->mutex_); 1971cb0ef41Sopenharmony_ci isolate = w_->isolate_; 1981cb0ef41Sopenharmony_ci w_->isolate_ = nullptr; 1991cb0ef41Sopenharmony_ci } 2001cb0ef41Sopenharmony_ci 2011cb0ef41Sopenharmony_ci if (isolate != nullptr) { 2021cb0ef41Sopenharmony_ci CHECK(!loop_init_failed_); 2031cb0ef41Sopenharmony_ci bool platform_finished = false; 2041cb0ef41Sopenharmony_ci 2051cb0ef41Sopenharmony_ci isolate_data_.reset(); 2061cb0ef41Sopenharmony_ci 2071cb0ef41Sopenharmony_ci w_->platform_->AddIsolateFinishedCallback(isolate, [](void* data) { 2081cb0ef41Sopenharmony_ci *static_cast<bool*>(data) = true; 2091cb0ef41Sopenharmony_ci }, &platform_finished); 2101cb0ef41Sopenharmony_ci 2111cb0ef41Sopenharmony_ci // The order of these calls is important; if the Isolate is first disposed 2121cb0ef41Sopenharmony_ci // and then unregistered, there is a race condition window in which no 2131cb0ef41Sopenharmony_ci // new Isolate at the same address can successfully be registered with 2141cb0ef41Sopenharmony_ci // the platform. 2151cb0ef41Sopenharmony_ci // (Refs: https://github.com/nodejs/node/issues/30846) 2161cb0ef41Sopenharmony_ci w_->platform_->UnregisterIsolate(isolate); 2171cb0ef41Sopenharmony_ci isolate->Dispose(); 2181cb0ef41Sopenharmony_ci 2191cb0ef41Sopenharmony_ci // Wait until the platform has cleaned up all relevant resources. 2201cb0ef41Sopenharmony_ci while (!platform_finished) { 2211cb0ef41Sopenharmony_ci uv_run(&loop_, UV_RUN_ONCE); 2221cb0ef41Sopenharmony_ci } 2231cb0ef41Sopenharmony_ci } 2241cb0ef41Sopenharmony_ci if (!loop_init_failed_) { 2251cb0ef41Sopenharmony_ci CheckedUvLoopClose(&loop_); 2261cb0ef41Sopenharmony_ci } 2271cb0ef41Sopenharmony_ci } 2281cb0ef41Sopenharmony_ci 2291cb0ef41Sopenharmony_ci bool loop_is_usable() const { return !loop_init_failed_; } 2301cb0ef41Sopenharmony_ci 2311cb0ef41Sopenharmony_ci private: 2321cb0ef41Sopenharmony_ci Worker* const w_; 2331cb0ef41Sopenharmony_ci uv_loop_t loop_; 2341cb0ef41Sopenharmony_ci bool loop_init_failed_ = true; 2351cb0ef41Sopenharmony_ci DeleteFnPtr<IsolateData, FreeIsolateData> isolate_data_; 2361cb0ef41Sopenharmony_ci const SnapshotData* snapshot_data_ = nullptr; 2371cb0ef41Sopenharmony_ci friend class Worker; 2381cb0ef41Sopenharmony_ci}; 2391cb0ef41Sopenharmony_ci 2401cb0ef41Sopenharmony_cisize_t Worker::NearHeapLimit(void* data, size_t current_heap_limit, 2411cb0ef41Sopenharmony_ci size_t initial_heap_limit) { 2421cb0ef41Sopenharmony_ci Worker* worker = static_cast<Worker*>(data); 2431cb0ef41Sopenharmony_ci // Give the current GC some extra leeway to let it finish rather than 2441cb0ef41Sopenharmony_ci // crash hard. We are not going to perform further allocations anyway. 2451cb0ef41Sopenharmony_ci constexpr size_t kExtraHeapAllowance = 16 * 1024 * 1024; 2461cb0ef41Sopenharmony_ci size_t new_limit = current_heap_limit + kExtraHeapAllowance; 2471cb0ef41Sopenharmony_ci Environment* env = worker->env(); 2481cb0ef41Sopenharmony_ci if (env != nullptr) { 2491cb0ef41Sopenharmony_ci DCHECK(!env->is_in_heapsnapshot_heap_limit_callback()); 2501cb0ef41Sopenharmony_ci Debug(env, 2511cb0ef41Sopenharmony_ci DebugCategory::DIAGNOSTICS, 2521cb0ef41Sopenharmony_ci "Throwing ERR_WORKER_OUT_OF_MEMORY, " 2531cb0ef41Sopenharmony_ci "new_limit=%" PRIu64 "\n", 2541cb0ef41Sopenharmony_ci static_cast<uint64_t>(new_limit)); 2551cb0ef41Sopenharmony_ci } 2561cb0ef41Sopenharmony_ci worker->Exit(1, "ERR_WORKER_OUT_OF_MEMORY", "JS heap out of memory"); 2571cb0ef41Sopenharmony_ci return new_limit; 2581cb0ef41Sopenharmony_ci} 2591cb0ef41Sopenharmony_ci 2601cb0ef41Sopenharmony_civoid Worker::Run() { 2611cb0ef41Sopenharmony_ci std::string trace_name = "[worker " + std::to_string(thread_id_.id) + "]" + 2621cb0ef41Sopenharmony_ci (name_ == "" ? "" : " " + name_); 2631cb0ef41Sopenharmony_ci TRACE_EVENT_METADATA1( 2641cb0ef41Sopenharmony_ci "__metadata", "thread_name", "name", TRACE_STR_COPY(trace_name.c_str())); 2651cb0ef41Sopenharmony_ci CHECK_NOT_NULL(platform_); 2661cb0ef41Sopenharmony_ci 2671cb0ef41Sopenharmony_ci Debug(this, "Creating isolate for worker with id %llu", thread_id_.id); 2681cb0ef41Sopenharmony_ci 2691cb0ef41Sopenharmony_ci WorkerThreadData data(this); 2701cb0ef41Sopenharmony_ci if (isolate_ == nullptr) return; 2711cb0ef41Sopenharmony_ci CHECK(data.loop_is_usable()); 2721cb0ef41Sopenharmony_ci 2731cb0ef41Sopenharmony_ci Debug(this, "Starting worker with id %llu", thread_id_.id); 2741cb0ef41Sopenharmony_ci { 2751cb0ef41Sopenharmony_ci Locker locker(isolate_); 2761cb0ef41Sopenharmony_ci Isolate::Scope isolate_scope(isolate_); 2771cb0ef41Sopenharmony_ci SealHandleScope outer_seal(isolate_); 2781cb0ef41Sopenharmony_ci 2791cb0ef41Sopenharmony_ci DeleteFnPtr<Environment, FreeEnvironment> env_; 2801cb0ef41Sopenharmony_ci auto cleanup_env = OnScopeLeave([&]() { 2811cb0ef41Sopenharmony_ci // TODO(addaleax): This call is harmless but should not be necessary. 2821cb0ef41Sopenharmony_ci // Figure out why V8 is raising a DCHECK() here without it 2831cb0ef41Sopenharmony_ci // (in test/parallel/test-async-hooks-worker-asyncfn-terminate-4.js). 2841cb0ef41Sopenharmony_ci isolate_->CancelTerminateExecution(); 2851cb0ef41Sopenharmony_ci 2861cb0ef41Sopenharmony_ci if (!env_) return; 2871cb0ef41Sopenharmony_ci env_->set_can_call_into_js(false); 2881cb0ef41Sopenharmony_ci 2891cb0ef41Sopenharmony_ci { 2901cb0ef41Sopenharmony_ci Mutex::ScopedLock lock(mutex_); 2911cb0ef41Sopenharmony_ci stopped_ = true; 2921cb0ef41Sopenharmony_ci this->env_ = nullptr; 2931cb0ef41Sopenharmony_ci } 2941cb0ef41Sopenharmony_ci 2951cb0ef41Sopenharmony_ci env_.reset(); 2961cb0ef41Sopenharmony_ci }); 2971cb0ef41Sopenharmony_ci 2981cb0ef41Sopenharmony_ci if (is_stopped()) return; 2991cb0ef41Sopenharmony_ci { 3001cb0ef41Sopenharmony_ci HandleScope handle_scope(isolate_); 3011cb0ef41Sopenharmony_ci Local<Context> context; 3021cb0ef41Sopenharmony_ci { 3031cb0ef41Sopenharmony_ci // We create the Context object before we have an Environment* in place 3041cb0ef41Sopenharmony_ci // that we could use for error handling. If creation fails due to 3051cb0ef41Sopenharmony_ci // resource constraints, we need something in place to handle it, 3061cb0ef41Sopenharmony_ci // though. 3071cb0ef41Sopenharmony_ci TryCatch try_catch(isolate_); 3081cb0ef41Sopenharmony_ci if (snapshot_data_ != nullptr) { 3091cb0ef41Sopenharmony_ci context = Context::FromSnapshot(isolate_, 3101cb0ef41Sopenharmony_ci SnapshotData::kNodeBaseContextIndex) 3111cb0ef41Sopenharmony_ci .ToLocalChecked(); 3121cb0ef41Sopenharmony_ci if (!context.IsEmpty() && 3131cb0ef41Sopenharmony_ci !InitializeContextRuntime(context).IsJust()) { 3141cb0ef41Sopenharmony_ci context = Local<Context>(); 3151cb0ef41Sopenharmony_ci } 3161cb0ef41Sopenharmony_ci } else { 3171cb0ef41Sopenharmony_ci context = NewContext(isolate_); 3181cb0ef41Sopenharmony_ci } 3191cb0ef41Sopenharmony_ci if (context.IsEmpty()) { 3201cb0ef41Sopenharmony_ci Exit(1, "ERR_WORKER_INIT_FAILED", "Failed to create new Context"); 3211cb0ef41Sopenharmony_ci return; 3221cb0ef41Sopenharmony_ci } 3231cb0ef41Sopenharmony_ci } 3241cb0ef41Sopenharmony_ci 3251cb0ef41Sopenharmony_ci if (is_stopped()) return; 3261cb0ef41Sopenharmony_ci CHECK(!context.IsEmpty()); 3271cb0ef41Sopenharmony_ci Context::Scope context_scope(context); 3281cb0ef41Sopenharmony_ci { 3291cb0ef41Sopenharmony_ci env_.reset(CreateEnvironment( 3301cb0ef41Sopenharmony_ci data.isolate_data_.get(), 3311cb0ef41Sopenharmony_ci context, 3321cb0ef41Sopenharmony_ci std::move(argv_), 3331cb0ef41Sopenharmony_ci std::move(exec_argv_), 3341cb0ef41Sopenharmony_ci static_cast<EnvironmentFlags::Flags>(environment_flags_), 3351cb0ef41Sopenharmony_ci thread_id_, 3361cb0ef41Sopenharmony_ci std::move(inspector_parent_handle_))); 3371cb0ef41Sopenharmony_ci if (is_stopped()) return; 3381cb0ef41Sopenharmony_ci CHECK_NOT_NULL(env_); 3391cb0ef41Sopenharmony_ci env_->set_env_vars(std::move(env_vars_)); 3401cb0ef41Sopenharmony_ci SetProcessExitHandler(env_.get(), [this](Environment*, int exit_code) { 3411cb0ef41Sopenharmony_ci Exit(exit_code); 3421cb0ef41Sopenharmony_ci }); 3431cb0ef41Sopenharmony_ci } 3441cb0ef41Sopenharmony_ci { 3451cb0ef41Sopenharmony_ci Mutex::ScopedLock lock(mutex_); 3461cb0ef41Sopenharmony_ci if (stopped_) return; 3471cb0ef41Sopenharmony_ci this->env_ = env_.get(); 3481cb0ef41Sopenharmony_ci } 3491cb0ef41Sopenharmony_ci Debug(this, "Created Environment for worker with id %llu", thread_id_.id); 3501cb0ef41Sopenharmony_ci if (is_stopped()) return; 3511cb0ef41Sopenharmony_ci { 3521cb0ef41Sopenharmony_ci if (!CreateEnvMessagePort(env_.get())) { 3531cb0ef41Sopenharmony_ci return; 3541cb0ef41Sopenharmony_ci } 3551cb0ef41Sopenharmony_ci 3561cb0ef41Sopenharmony_ci Debug(this, "Created message port for worker %llu", thread_id_.id); 3571cb0ef41Sopenharmony_ci if (LoadEnvironment(env_.get(), StartExecutionCallback{}).IsEmpty()) 3581cb0ef41Sopenharmony_ci return; 3591cb0ef41Sopenharmony_ci 3601cb0ef41Sopenharmony_ci Debug(this, "Loaded environment for worker %llu", thread_id_.id); 3611cb0ef41Sopenharmony_ci } 3621cb0ef41Sopenharmony_ci } 3631cb0ef41Sopenharmony_ci 3641cb0ef41Sopenharmony_ci { 3651cb0ef41Sopenharmony_ci Maybe<int> exit_code = SpinEventLoop(env_.get()); 3661cb0ef41Sopenharmony_ci Mutex::ScopedLock lock(mutex_); 3671cb0ef41Sopenharmony_ci if (exit_code_ == 0 && exit_code.IsJust()) { 3681cb0ef41Sopenharmony_ci exit_code_ = exit_code.FromJust(); 3691cb0ef41Sopenharmony_ci } 3701cb0ef41Sopenharmony_ci 3711cb0ef41Sopenharmony_ci Debug(this, "Exiting thread for worker %llu with exit code %d", 3721cb0ef41Sopenharmony_ci thread_id_.id, exit_code_); 3731cb0ef41Sopenharmony_ci } 3741cb0ef41Sopenharmony_ci } 3751cb0ef41Sopenharmony_ci 3761cb0ef41Sopenharmony_ci Debug(this, "Worker %llu thread stops", thread_id_.id); 3771cb0ef41Sopenharmony_ci} 3781cb0ef41Sopenharmony_ci 3791cb0ef41Sopenharmony_cibool Worker::CreateEnvMessagePort(Environment* env) { 3801cb0ef41Sopenharmony_ci HandleScope handle_scope(isolate_); 3811cb0ef41Sopenharmony_ci std::unique_ptr<MessagePortData> data; 3821cb0ef41Sopenharmony_ci { 3831cb0ef41Sopenharmony_ci Mutex::ScopedLock lock(mutex_); 3841cb0ef41Sopenharmony_ci data = std::move(child_port_data_); 3851cb0ef41Sopenharmony_ci } 3861cb0ef41Sopenharmony_ci 3871cb0ef41Sopenharmony_ci // Set up the message channel for receiving messages in the child. 3881cb0ef41Sopenharmony_ci MessagePort* child_port = MessagePort::New(env, 3891cb0ef41Sopenharmony_ci env->context(), 3901cb0ef41Sopenharmony_ci std::move(data)); 3911cb0ef41Sopenharmony_ci // MessagePort::New() may return nullptr if execution is terminated 3921cb0ef41Sopenharmony_ci // within it. 3931cb0ef41Sopenharmony_ci if (child_port != nullptr) 3941cb0ef41Sopenharmony_ci env->set_message_port(child_port->object(isolate_)); 3951cb0ef41Sopenharmony_ci 3961cb0ef41Sopenharmony_ci return child_port; 3971cb0ef41Sopenharmony_ci} 3981cb0ef41Sopenharmony_ci 3991cb0ef41Sopenharmony_civoid Worker::JoinThread() { 4001cb0ef41Sopenharmony_ci if (!tid_.has_value()) 4011cb0ef41Sopenharmony_ci return; 4021cb0ef41Sopenharmony_ci CHECK_EQ(uv_thread_join(&tid_.value()), 0); 4031cb0ef41Sopenharmony_ci tid_.reset(); 4041cb0ef41Sopenharmony_ci 4051cb0ef41Sopenharmony_ci env()->remove_sub_worker_context(this); 4061cb0ef41Sopenharmony_ci 4071cb0ef41Sopenharmony_ci { 4081cb0ef41Sopenharmony_ci HandleScope handle_scope(env()->isolate()); 4091cb0ef41Sopenharmony_ci Context::Scope context_scope(env()->context()); 4101cb0ef41Sopenharmony_ci 4111cb0ef41Sopenharmony_ci // Reset the parent port as we're closing it now anyway. 4121cb0ef41Sopenharmony_ci object()->Set(env()->context(), 4131cb0ef41Sopenharmony_ci env()->message_port_string(), 4141cb0ef41Sopenharmony_ci Undefined(env()->isolate())).Check(); 4151cb0ef41Sopenharmony_ci 4161cb0ef41Sopenharmony_ci Local<Value> args[] = { 4171cb0ef41Sopenharmony_ci Integer::New(env()->isolate(), exit_code_), 4181cb0ef41Sopenharmony_ci custom_error_ != nullptr 4191cb0ef41Sopenharmony_ci ? OneByteString(env()->isolate(), custom_error_).As<Value>() 4201cb0ef41Sopenharmony_ci : Null(env()->isolate()).As<Value>(), 4211cb0ef41Sopenharmony_ci !custom_error_str_.empty() 4221cb0ef41Sopenharmony_ci ? OneByteString(env()->isolate(), custom_error_str_.c_str()) 4231cb0ef41Sopenharmony_ci .As<Value>() 4241cb0ef41Sopenharmony_ci : Null(env()->isolate()).As<Value>(), 4251cb0ef41Sopenharmony_ci }; 4261cb0ef41Sopenharmony_ci 4271cb0ef41Sopenharmony_ci MakeCallback(env()->onexit_string(), arraysize(args), args); 4281cb0ef41Sopenharmony_ci } 4291cb0ef41Sopenharmony_ci 4301cb0ef41Sopenharmony_ci // If we get here, the tid_.has_value() condition at the top of the function 4311cb0ef41Sopenharmony_ci // implies that the thread was running. In that case, its final action will 4321cb0ef41Sopenharmony_ci // be to schedule a callback on the parent thread which will delete this 4331cb0ef41Sopenharmony_ci // object, so there's nothing more to do here. 4341cb0ef41Sopenharmony_ci} 4351cb0ef41Sopenharmony_ci 4361cb0ef41Sopenharmony_ciWorker::~Worker() { 4371cb0ef41Sopenharmony_ci Mutex::ScopedLock lock(mutex_); 4381cb0ef41Sopenharmony_ci 4391cb0ef41Sopenharmony_ci CHECK(stopped_); 4401cb0ef41Sopenharmony_ci CHECK_NULL(env_); 4411cb0ef41Sopenharmony_ci CHECK(!tid_.has_value()); 4421cb0ef41Sopenharmony_ci 4431cb0ef41Sopenharmony_ci Debug(this, "Worker %llu destroyed", thread_id_.id); 4441cb0ef41Sopenharmony_ci} 4451cb0ef41Sopenharmony_ci 4461cb0ef41Sopenharmony_civoid Worker::New(const FunctionCallbackInfo<Value>& args) { 4471cb0ef41Sopenharmony_ci Environment* env = Environment::GetCurrent(args); 4481cb0ef41Sopenharmony_ci auto is_internal = args[5]; 4491cb0ef41Sopenharmony_ci CHECK(is_internal->IsBoolean()); 4501cb0ef41Sopenharmony_ci Isolate* isolate = args.GetIsolate(); 4511cb0ef41Sopenharmony_ci 4521cb0ef41Sopenharmony_ci CHECK(args.IsConstructCall()); 4531cb0ef41Sopenharmony_ci 4541cb0ef41Sopenharmony_ci if (env->isolate_data()->platform() == nullptr) { 4551cb0ef41Sopenharmony_ci THROW_ERR_MISSING_PLATFORM_FOR_WORKER(env); 4561cb0ef41Sopenharmony_ci return; 4571cb0ef41Sopenharmony_ci } 4581cb0ef41Sopenharmony_ci 4591cb0ef41Sopenharmony_ci std::string url; 4601cb0ef41Sopenharmony_ci std::string name; 4611cb0ef41Sopenharmony_ci std::shared_ptr<PerIsolateOptions> per_isolate_opts = nullptr; 4621cb0ef41Sopenharmony_ci std::shared_ptr<KVStore> env_vars = nullptr; 4631cb0ef41Sopenharmony_ci 4641cb0ef41Sopenharmony_ci std::vector<std::string> exec_argv_out; 4651cb0ef41Sopenharmony_ci 4661cb0ef41Sopenharmony_ci // Argument might be a string or URL 4671cb0ef41Sopenharmony_ci if (!args[0]->IsNullOrUndefined()) { 4681cb0ef41Sopenharmony_ci Utf8Value value( 4691cb0ef41Sopenharmony_ci isolate, args[0]->ToString(env->context()).FromMaybe(Local<String>())); 4701cb0ef41Sopenharmony_ci url.append(value.out(), value.length()); 4711cb0ef41Sopenharmony_ci } 4721cb0ef41Sopenharmony_ci 4731cb0ef41Sopenharmony_ci if (!args[6]->IsNullOrUndefined()) { 4741cb0ef41Sopenharmony_ci Utf8Value value( 4751cb0ef41Sopenharmony_ci isolate, args[6]->ToString(env->context()).FromMaybe(Local<String>())); 4761cb0ef41Sopenharmony_ci name.append(value.out(), value.length()); 4771cb0ef41Sopenharmony_ci } 4781cb0ef41Sopenharmony_ci 4791cb0ef41Sopenharmony_ci if (args[1]->IsNull()) { 4801cb0ef41Sopenharmony_ci // Means worker.env = { ...process.env }. 4811cb0ef41Sopenharmony_ci env_vars = env->env_vars()->Clone(isolate); 4821cb0ef41Sopenharmony_ci } else if (args[1]->IsObject()) { 4831cb0ef41Sopenharmony_ci // User provided env. 4841cb0ef41Sopenharmony_ci env_vars = KVStore::CreateMapKVStore(); 4851cb0ef41Sopenharmony_ci env_vars->AssignFromObject(isolate->GetCurrentContext(), 4861cb0ef41Sopenharmony_ci args[1].As<Object>()); 4871cb0ef41Sopenharmony_ci } else { 4881cb0ef41Sopenharmony_ci // Env is shared. 4891cb0ef41Sopenharmony_ci env_vars = env->env_vars(); 4901cb0ef41Sopenharmony_ci } 4911cb0ef41Sopenharmony_ci 4921cb0ef41Sopenharmony_ci if (args[1]->IsObject() || args[2]->IsArray()) { 4931cb0ef41Sopenharmony_ci per_isolate_opts.reset(new PerIsolateOptions()); 4941cb0ef41Sopenharmony_ci 4951cb0ef41Sopenharmony_ci HandleEnvOptions(per_isolate_opts->per_env, [&env_vars](const char* name) { 4961cb0ef41Sopenharmony_ci return env_vars->Get(name).FromMaybe(""); 4971cb0ef41Sopenharmony_ci }); 4981cb0ef41Sopenharmony_ci 4991cb0ef41Sopenharmony_ci#ifndef NODE_WITHOUT_NODE_OPTIONS 5001cb0ef41Sopenharmony_ci MaybeLocal<String> maybe_node_opts = 5011cb0ef41Sopenharmony_ci env_vars->Get(isolate, OneByteString(isolate, "NODE_OPTIONS")); 5021cb0ef41Sopenharmony_ci Local<String> node_opts; 5031cb0ef41Sopenharmony_ci if (maybe_node_opts.ToLocal(&node_opts)) { 5041cb0ef41Sopenharmony_ci std::string node_options(*String::Utf8Value(isolate, node_opts)); 5051cb0ef41Sopenharmony_ci std::vector<std::string> errors{}; 5061cb0ef41Sopenharmony_ci std::vector<std::string> env_argv = 5071cb0ef41Sopenharmony_ci ParseNodeOptionsEnvVar(node_options, &errors); 5081cb0ef41Sopenharmony_ci // [0] is expected to be the program name, add dummy string. 5091cb0ef41Sopenharmony_ci env_argv.insert(env_argv.begin(), ""); 5101cb0ef41Sopenharmony_ci std::vector<std::string> invalid_args{}; 5111cb0ef41Sopenharmony_ci options_parser::Parse(&env_argv, 5121cb0ef41Sopenharmony_ci nullptr, 5131cb0ef41Sopenharmony_ci &invalid_args, 5141cb0ef41Sopenharmony_ci per_isolate_opts.get(), 5151cb0ef41Sopenharmony_ci kAllowedInEnvvar, 5161cb0ef41Sopenharmony_ci &errors); 5171cb0ef41Sopenharmony_ci if (!errors.empty() && args[1]->IsObject()) { 5181cb0ef41Sopenharmony_ci // Only fail for explicitly provided env, this protects from failures 5191cb0ef41Sopenharmony_ci // when NODE_OPTIONS from parent's env is used (which is the default). 5201cb0ef41Sopenharmony_ci Local<Value> error; 5211cb0ef41Sopenharmony_ci if (!ToV8Value(env->context(), errors).ToLocal(&error)) return; 5221cb0ef41Sopenharmony_ci Local<String> key = 5231cb0ef41Sopenharmony_ci FIXED_ONE_BYTE_STRING(env->isolate(), "invalidNodeOptions"); 5241cb0ef41Sopenharmony_ci // Ignore the return value of Set() because exceptions bubble up to JS 5251cb0ef41Sopenharmony_ci // when we return anyway. 5261cb0ef41Sopenharmony_ci USE(args.This()->Set(env->context(), key, error)); 5271cb0ef41Sopenharmony_ci return; 5281cb0ef41Sopenharmony_ci } 5291cb0ef41Sopenharmony_ci } 5301cb0ef41Sopenharmony_ci#endif // NODE_WITHOUT_NODE_OPTIONS 5311cb0ef41Sopenharmony_ci } 5321cb0ef41Sopenharmony_ci 5331cb0ef41Sopenharmony_ci if (args[2]->IsArray()) { 5341cb0ef41Sopenharmony_ci Local<Array> array = args[2].As<Array>(); 5351cb0ef41Sopenharmony_ci // The first argument is reserved for program name, but we don't need it 5361cb0ef41Sopenharmony_ci // in workers. 5371cb0ef41Sopenharmony_ci std::vector<std::string> exec_argv = {""}; 5381cb0ef41Sopenharmony_ci uint32_t length = array->Length(); 5391cb0ef41Sopenharmony_ci for (uint32_t i = 0; i < length; i++) { 5401cb0ef41Sopenharmony_ci Local<Value> arg; 5411cb0ef41Sopenharmony_ci if (!array->Get(env->context(), i).ToLocal(&arg)) { 5421cb0ef41Sopenharmony_ci return; 5431cb0ef41Sopenharmony_ci } 5441cb0ef41Sopenharmony_ci Local<String> arg_v8; 5451cb0ef41Sopenharmony_ci if (!arg->ToString(env->context()).ToLocal(&arg_v8)) { 5461cb0ef41Sopenharmony_ci return; 5471cb0ef41Sopenharmony_ci } 5481cb0ef41Sopenharmony_ci Utf8Value arg_utf8_value(args.GetIsolate(), arg_v8); 5491cb0ef41Sopenharmony_ci std::string arg_string(arg_utf8_value.out(), arg_utf8_value.length()); 5501cb0ef41Sopenharmony_ci exec_argv.push_back(arg_string); 5511cb0ef41Sopenharmony_ci } 5521cb0ef41Sopenharmony_ci 5531cb0ef41Sopenharmony_ci std::vector<std::string> invalid_args{}; 5541cb0ef41Sopenharmony_ci std::vector<std::string> errors{}; 5551cb0ef41Sopenharmony_ci // Using invalid_args as the v8_args argument as it stores unknown 5561cb0ef41Sopenharmony_ci // options for the per isolate parser. 5571cb0ef41Sopenharmony_ci options_parser::Parse(&exec_argv, 5581cb0ef41Sopenharmony_ci &exec_argv_out, 5591cb0ef41Sopenharmony_ci &invalid_args, 5601cb0ef41Sopenharmony_ci per_isolate_opts.get(), 5611cb0ef41Sopenharmony_ci kDisallowedInEnvvar, 5621cb0ef41Sopenharmony_ci &errors); 5631cb0ef41Sopenharmony_ci 5641cb0ef41Sopenharmony_ci // The first argument is program name. 5651cb0ef41Sopenharmony_ci invalid_args.erase(invalid_args.begin()); 5661cb0ef41Sopenharmony_ci if (errors.size() > 0 || invalid_args.size() > 0) { 5671cb0ef41Sopenharmony_ci Local<Value> error; 5681cb0ef41Sopenharmony_ci if (!ToV8Value(env->context(), 5691cb0ef41Sopenharmony_ci errors.size() > 0 ? errors : invalid_args) 5701cb0ef41Sopenharmony_ci .ToLocal(&error)) { 5711cb0ef41Sopenharmony_ci return; 5721cb0ef41Sopenharmony_ci } 5731cb0ef41Sopenharmony_ci Local<String> key = 5741cb0ef41Sopenharmony_ci FIXED_ONE_BYTE_STRING(env->isolate(), "invalidExecArgv"); 5751cb0ef41Sopenharmony_ci // Ignore the return value of Set() because exceptions bubble up to JS 5761cb0ef41Sopenharmony_ci // when we return anyway. 5771cb0ef41Sopenharmony_ci USE(args.This()->Set(env->context(), key, error)); 5781cb0ef41Sopenharmony_ci return; 5791cb0ef41Sopenharmony_ci } 5801cb0ef41Sopenharmony_ci } else { 5811cb0ef41Sopenharmony_ci exec_argv_out = env->exec_argv(); 5821cb0ef41Sopenharmony_ci } 5831cb0ef41Sopenharmony_ci 5841cb0ef41Sopenharmony_ci bool use_node_snapshot = per_process::cli_options->node_snapshot; 5851cb0ef41Sopenharmony_ci const SnapshotData* snapshot_data = 5861cb0ef41Sopenharmony_ci use_node_snapshot ? SnapshotBuilder::GetEmbeddedSnapshotData() : nullptr; 5871cb0ef41Sopenharmony_ci 5881cb0ef41Sopenharmony_ci Worker* worker = new Worker(env, 5891cb0ef41Sopenharmony_ci args.This(), 5901cb0ef41Sopenharmony_ci url, 5911cb0ef41Sopenharmony_ci name, 5921cb0ef41Sopenharmony_ci per_isolate_opts, 5931cb0ef41Sopenharmony_ci std::move(exec_argv_out), 5941cb0ef41Sopenharmony_ci env_vars, 5951cb0ef41Sopenharmony_ci snapshot_data); 5961cb0ef41Sopenharmony_ci 5971cb0ef41Sopenharmony_ci CHECK(args[3]->IsFloat64Array()); 5981cb0ef41Sopenharmony_ci Local<Float64Array> limit_info = args[3].As<Float64Array>(); 5991cb0ef41Sopenharmony_ci CHECK_EQ(limit_info->Length(), kTotalResourceLimitCount); 6001cb0ef41Sopenharmony_ci limit_info->CopyContents(worker->resource_limits_, 6011cb0ef41Sopenharmony_ci sizeof(worker->resource_limits_)); 6021cb0ef41Sopenharmony_ci 6031cb0ef41Sopenharmony_ci CHECK(args[4]->IsBoolean()); 6041cb0ef41Sopenharmony_ci if (args[4]->IsTrue() || env->tracks_unmanaged_fds()) 6051cb0ef41Sopenharmony_ci worker->environment_flags_ |= EnvironmentFlags::kTrackUnmanagedFds; 6061cb0ef41Sopenharmony_ci if (env->hide_console_windows()) 6071cb0ef41Sopenharmony_ci worker->environment_flags_ |= EnvironmentFlags::kHideConsoleWindows; 6081cb0ef41Sopenharmony_ci if (env->no_native_addons()) 6091cb0ef41Sopenharmony_ci worker->environment_flags_ |= EnvironmentFlags::kNoNativeAddons; 6101cb0ef41Sopenharmony_ci if (env->no_global_search_paths()) 6111cb0ef41Sopenharmony_ci worker->environment_flags_ |= EnvironmentFlags::kNoGlobalSearchPaths; 6121cb0ef41Sopenharmony_ci if (env->no_browser_globals()) 6131cb0ef41Sopenharmony_ci worker->environment_flags_ |= EnvironmentFlags::kNoBrowserGlobals; 6141cb0ef41Sopenharmony_ci} 6151cb0ef41Sopenharmony_ci 6161cb0ef41Sopenharmony_civoid Worker::StartThread(const FunctionCallbackInfo<Value>& args) { 6171cb0ef41Sopenharmony_ci Worker* w; 6181cb0ef41Sopenharmony_ci ASSIGN_OR_RETURN_UNWRAP(&w, args.This()); 6191cb0ef41Sopenharmony_ci Mutex::ScopedLock lock(w->mutex_); 6201cb0ef41Sopenharmony_ci 6211cb0ef41Sopenharmony_ci w->stopped_ = false; 6221cb0ef41Sopenharmony_ci 6231cb0ef41Sopenharmony_ci if (w->resource_limits_[kStackSizeMb] > 0) { 6241cb0ef41Sopenharmony_ci if (w->resource_limits_[kStackSizeMb] * kMB < kStackBufferSize) { 6251cb0ef41Sopenharmony_ci w->resource_limits_[kStackSizeMb] = kStackBufferSize / kMB; 6261cb0ef41Sopenharmony_ci w->stack_size_ = kStackBufferSize; 6271cb0ef41Sopenharmony_ci } else { 6281cb0ef41Sopenharmony_ci w->stack_size_ = 6291cb0ef41Sopenharmony_ci static_cast<size_t>(w->resource_limits_[kStackSizeMb] * kMB); 6301cb0ef41Sopenharmony_ci } 6311cb0ef41Sopenharmony_ci } else { 6321cb0ef41Sopenharmony_ci w->resource_limits_[kStackSizeMb] = w->stack_size_ / kMB; 6331cb0ef41Sopenharmony_ci } 6341cb0ef41Sopenharmony_ci 6351cb0ef41Sopenharmony_ci uv_thread_options_t thread_options; 6361cb0ef41Sopenharmony_ci thread_options.flags = UV_THREAD_HAS_STACK_SIZE; 6371cb0ef41Sopenharmony_ci thread_options.stack_size = w->stack_size_; 6381cb0ef41Sopenharmony_ci 6391cb0ef41Sopenharmony_ci uv_thread_t* tid = &w->tid_.emplace(); // Create uv_thread_t instance 6401cb0ef41Sopenharmony_ci int ret = uv_thread_create_ex(tid, &thread_options, [](void* arg) { 6411cb0ef41Sopenharmony_ci // XXX: This could become a std::unique_ptr, but that makes at least 6421cb0ef41Sopenharmony_ci // gcc 6.3 detect undefined behaviour when there shouldn't be any. 6431cb0ef41Sopenharmony_ci // gcc 7+ handles this well. 6441cb0ef41Sopenharmony_ci Worker* w = static_cast<Worker*>(arg); 6451cb0ef41Sopenharmony_ci const uintptr_t stack_top = reinterpret_cast<uintptr_t>(&arg); 6461cb0ef41Sopenharmony_ci 6471cb0ef41Sopenharmony_ci // Leave a few kilobytes just to make sure we're within limits and have 6481cb0ef41Sopenharmony_ci // some space to do work in C++ land. 6491cb0ef41Sopenharmony_ci w->stack_base_ = stack_top - (w->stack_size_ - kStackBufferSize); 6501cb0ef41Sopenharmony_ci 6511cb0ef41Sopenharmony_ci w->Run(); 6521cb0ef41Sopenharmony_ci 6531cb0ef41Sopenharmony_ci Mutex::ScopedLock lock(w->mutex_); 6541cb0ef41Sopenharmony_ci w->env()->SetImmediateThreadsafe( 6551cb0ef41Sopenharmony_ci [w = std::unique_ptr<Worker>(w)](Environment* env) { 6561cb0ef41Sopenharmony_ci if (w->has_ref_) 6571cb0ef41Sopenharmony_ci env->add_refs(-1); 6581cb0ef41Sopenharmony_ci w->JoinThread(); 6591cb0ef41Sopenharmony_ci // implicitly delete w 6601cb0ef41Sopenharmony_ci }); 6611cb0ef41Sopenharmony_ci }, static_cast<void*>(w)); 6621cb0ef41Sopenharmony_ci 6631cb0ef41Sopenharmony_ci if (ret == 0) { 6641cb0ef41Sopenharmony_ci // The object now owns the created thread and should not be garbage 6651cb0ef41Sopenharmony_ci // collected until that finishes. 6661cb0ef41Sopenharmony_ci w->ClearWeak(); 6671cb0ef41Sopenharmony_ci 6681cb0ef41Sopenharmony_ci if (w->has_ref_) 6691cb0ef41Sopenharmony_ci w->env()->add_refs(1); 6701cb0ef41Sopenharmony_ci 6711cb0ef41Sopenharmony_ci w->env()->add_sub_worker_context(w); 6721cb0ef41Sopenharmony_ci } else { 6731cb0ef41Sopenharmony_ci w->stopped_ = true; 6741cb0ef41Sopenharmony_ci w->tid_.reset(); 6751cb0ef41Sopenharmony_ci 6761cb0ef41Sopenharmony_ci char err_buf[128]; 6771cb0ef41Sopenharmony_ci uv_err_name_r(ret, err_buf, sizeof(err_buf)); 6781cb0ef41Sopenharmony_ci { 6791cb0ef41Sopenharmony_ci Isolate* isolate = w->env()->isolate(); 6801cb0ef41Sopenharmony_ci HandleScope handle_scope(isolate); 6811cb0ef41Sopenharmony_ci THROW_ERR_WORKER_INIT_FAILED(isolate, err_buf); 6821cb0ef41Sopenharmony_ci } 6831cb0ef41Sopenharmony_ci } 6841cb0ef41Sopenharmony_ci} 6851cb0ef41Sopenharmony_ci 6861cb0ef41Sopenharmony_civoid Worker::StopThread(const FunctionCallbackInfo<Value>& args) { 6871cb0ef41Sopenharmony_ci Worker* w; 6881cb0ef41Sopenharmony_ci ASSIGN_OR_RETURN_UNWRAP(&w, args.This()); 6891cb0ef41Sopenharmony_ci 6901cb0ef41Sopenharmony_ci Debug(w, "Worker %llu is getting stopped by parent", w->thread_id_.id); 6911cb0ef41Sopenharmony_ci w->Exit(1); 6921cb0ef41Sopenharmony_ci} 6931cb0ef41Sopenharmony_ci 6941cb0ef41Sopenharmony_civoid Worker::Ref(const FunctionCallbackInfo<Value>& args) { 6951cb0ef41Sopenharmony_ci Worker* w; 6961cb0ef41Sopenharmony_ci ASSIGN_OR_RETURN_UNWRAP(&w, args.This()); 6971cb0ef41Sopenharmony_ci if (!w->has_ref_ && w->tid_.has_value()) { 6981cb0ef41Sopenharmony_ci w->has_ref_ = true; 6991cb0ef41Sopenharmony_ci w->env()->add_refs(1); 7001cb0ef41Sopenharmony_ci } 7011cb0ef41Sopenharmony_ci} 7021cb0ef41Sopenharmony_ci 7031cb0ef41Sopenharmony_civoid Worker::HasRef(const FunctionCallbackInfo<Value>& args) { 7041cb0ef41Sopenharmony_ci Worker* w; 7051cb0ef41Sopenharmony_ci ASSIGN_OR_RETURN_UNWRAP(&w, args.This()); 7061cb0ef41Sopenharmony_ci args.GetReturnValue().Set(w->has_ref_); 7071cb0ef41Sopenharmony_ci} 7081cb0ef41Sopenharmony_ci 7091cb0ef41Sopenharmony_civoid Worker::Unref(const FunctionCallbackInfo<Value>& args) { 7101cb0ef41Sopenharmony_ci Worker* w; 7111cb0ef41Sopenharmony_ci ASSIGN_OR_RETURN_UNWRAP(&w, args.This()); 7121cb0ef41Sopenharmony_ci if (w->has_ref_ && w->tid_.has_value()) { 7131cb0ef41Sopenharmony_ci w->has_ref_ = false; 7141cb0ef41Sopenharmony_ci w->env()->add_refs(-1); 7151cb0ef41Sopenharmony_ci } 7161cb0ef41Sopenharmony_ci} 7171cb0ef41Sopenharmony_ci 7181cb0ef41Sopenharmony_civoid Worker::GetResourceLimits(const FunctionCallbackInfo<Value>& args) { 7191cb0ef41Sopenharmony_ci Worker* w; 7201cb0ef41Sopenharmony_ci ASSIGN_OR_RETURN_UNWRAP(&w, args.This()); 7211cb0ef41Sopenharmony_ci args.GetReturnValue().Set(w->GetResourceLimits(args.GetIsolate())); 7221cb0ef41Sopenharmony_ci} 7231cb0ef41Sopenharmony_ci 7241cb0ef41Sopenharmony_ciLocal<Float64Array> Worker::GetResourceLimits(Isolate* isolate) const { 7251cb0ef41Sopenharmony_ci Local<ArrayBuffer> ab = ArrayBuffer::New(isolate, sizeof(resource_limits_)); 7261cb0ef41Sopenharmony_ci 7271cb0ef41Sopenharmony_ci memcpy(ab->Data(), resource_limits_, sizeof(resource_limits_)); 7281cb0ef41Sopenharmony_ci return Float64Array::New(ab, 0, kTotalResourceLimitCount); 7291cb0ef41Sopenharmony_ci} 7301cb0ef41Sopenharmony_ci 7311cb0ef41Sopenharmony_civoid Worker::Exit(int code, const char* error_code, const char* error_message) { 7321cb0ef41Sopenharmony_ci Mutex::ScopedLock lock(mutex_); 7331cb0ef41Sopenharmony_ci Debug(this, "Worker %llu called Exit(%d, %s, %s)", 7341cb0ef41Sopenharmony_ci thread_id_.id, code, error_code, error_message); 7351cb0ef41Sopenharmony_ci 7361cb0ef41Sopenharmony_ci if (error_code != nullptr) { 7371cb0ef41Sopenharmony_ci custom_error_ = error_code; 7381cb0ef41Sopenharmony_ci custom_error_str_ = error_message; 7391cb0ef41Sopenharmony_ci } 7401cb0ef41Sopenharmony_ci 7411cb0ef41Sopenharmony_ci if (env_ != nullptr) { 7421cb0ef41Sopenharmony_ci exit_code_ = code; 7431cb0ef41Sopenharmony_ci Stop(env_); 7441cb0ef41Sopenharmony_ci } else { 7451cb0ef41Sopenharmony_ci stopped_ = true; 7461cb0ef41Sopenharmony_ci } 7471cb0ef41Sopenharmony_ci} 7481cb0ef41Sopenharmony_ci 7491cb0ef41Sopenharmony_cibool Worker::IsNotIndicativeOfMemoryLeakAtExit() const { 7501cb0ef41Sopenharmony_ci // Worker objects always stay alive as long as the child thread, regardless 7511cb0ef41Sopenharmony_ci // of whether they are being referenced in the parent thread. 7521cb0ef41Sopenharmony_ci return true; 7531cb0ef41Sopenharmony_ci} 7541cb0ef41Sopenharmony_ci 7551cb0ef41Sopenharmony_ciclass WorkerHeapSnapshotTaker : public AsyncWrap { 7561cb0ef41Sopenharmony_ci public: 7571cb0ef41Sopenharmony_ci WorkerHeapSnapshotTaker(Environment* env, Local<Object> obj) 7581cb0ef41Sopenharmony_ci : AsyncWrap(env, obj, AsyncWrap::PROVIDER_WORKERHEAPSNAPSHOT) {} 7591cb0ef41Sopenharmony_ci 7601cb0ef41Sopenharmony_ci SET_NO_MEMORY_INFO() 7611cb0ef41Sopenharmony_ci SET_MEMORY_INFO_NAME(WorkerHeapSnapshotTaker) 7621cb0ef41Sopenharmony_ci SET_SELF_SIZE(WorkerHeapSnapshotTaker) 7631cb0ef41Sopenharmony_ci}; 7641cb0ef41Sopenharmony_ci 7651cb0ef41Sopenharmony_civoid Worker::TakeHeapSnapshot(const FunctionCallbackInfo<Value>& args) { 7661cb0ef41Sopenharmony_ci Worker* w; 7671cb0ef41Sopenharmony_ci ASSIGN_OR_RETURN_UNWRAP(&w, args.This()); 7681cb0ef41Sopenharmony_ci 7691cb0ef41Sopenharmony_ci Debug(w, "Worker %llu taking heap snapshot", w->thread_id_.id); 7701cb0ef41Sopenharmony_ci 7711cb0ef41Sopenharmony_ci Environment* env = w->env(); 7721cb0ef41Sopenharmony_ci AsyncHooks::DefaultTriggerAsyncIdScope trigger_id_scope(w); 7731cb0ef41Sopenharmony_ci Local<Object> wrap; 7741cb0ef41Sopenharmony_ci if (!env->worker_heap_snapshot_taker_template() 7751cb0ef41Sopenharmony_ci ->NewInstance(env->context()).ToLocal(&wrap)) { 7761cb0ef41Sopenharmony_ci return; 7771cb0ef41Sopenharmony_ci } 7781cb0ef41Sopenharmony_ci 7791cb0ef41Sopenharmony_ci // The created WorkerHeapSnapshotTaker is an object owned by main 7801cb0ef41Sopenharmony_ci // thread's Isolate, it can not be accessed by worker thread 7811cb0ef41Sopenharmony_ci std::unique_ptr<BaseObjectPtr<WorkerHeapSnapshotTaker>> taker = 7821cb0ef41Sopenharmony_ci std::make_unique<BaseObjectPtr<WorkerHeapSnapshotTaker>>( 7831cb0ef41Sopenharmony_ci MakeDetachedBaseObject<WorkerHeapSnapshotTaker>(env, wrap)); 7841cb0ef41Sopenharmony_ci 7851cb0ef41Sopenharmony_ci // Interrupt the worker thread and take a snapshot, then schedule a call 7861cb0ef41Sopenharmony_ci // on the parent thread that turns that snapshot into a readable stream. 7871cb0ef41Sopenharmony_ci bool scheduled = w->RequestInterrupt([taker = std::move(taker), 7881cb0ef41Sopenharmony_ci env](Environment* worker_env) mutable { 7891cb0ef41Sopenharmony_ci heap::HeapSnapshotPointer snapshot{ 7901cb0ef41Sopenharmony_ci worker_env->isolate()->GetHeapProfiler()->TakeHeapSnapshot()}; 7911cb0ef41Sopenharmony_ci CHECK(snapshot); 7921cb0ef41Sopenharmony_ci 7931cb0ef41Sopenharmony_ci // Here, the worker thread temporarily owns the WorkerHeapSnapshotTaker 7941cb0ef41Sopenharmony_ci // object. 7951cb0ef41Sopenharmony_ci 7961cb0ef41Sopenharmony_ci env->SetImmediateThreadsafe( 7971cb0ef41Sopenharmony_ci [taker = std::move(taker), 7981cb0ef41Sopenharmony_ci snapshot = std::move(snapshot)](Environment* env) mutable { 7991cb0ef41Sopenharmony_ci HandleScope handle_scope(env->isolate()); 8001cb0ef41Sopenharmony_ci Context::Scope context_scope(env->context()); 8011cb0ef41Sopenharmony_ci 8021cb0ef41Sopenharmony_ci AsyncHooks::DefaultTriggerAsyncIdScope trigger_id_scope(taker->get()); 8031cb0ef41Sopenharmony_ci BaseObjectPtr<AsyncWrap> stream = 8041cb0ef41Sopenharmony_ci heap::CreateHeapSnapshotStream(env, std::move(snapshot)); 8051cb0ef41Sopenharmony_ci Local<Value> args[] = {stream->object()}; 8061cb0ef41Sopenharmony_ci taker->get()->MakeCallback( 8071cb0ef41Sopenharmony_ci env->ondone_string(), arraysize(args), args); 8081cb0ef41Sopenharmony_ci // implicitly delete `taker` 8091cb0ef41Sopenharmony_ci }, 8101cb0ef41Sopenharmony_ci CallbackFlags::kUnrefed); 8111cb0ef41Sopenharmony_ci 8121cb0ef41Sopenharmony_ci // Now, the lambda is delivered to the main thread, as a result, the 8131cb0ef41Sopenharmony_ci // WorkerHeapSnapshotTaker object is delivered to the main thread, too. 8141cb0ef41Sopenharmony_ci }); 8151cb0ef41Sopenharmony_ci 8161cb0ef41Sopenharmony_ci if (scheduled) { 8171cb0ef41Sopenharmony_ci args.GetReturnValue().Set(wrap); 8181cb0ef41Sopenharmony_ci } else { 8191cb0ef41Sopenharmony_ci args.GetReturnValue().Set(Local<Object>()); 8201cb0ef41Sopenharmony_ci } 8211cb0ef41Sopenharmony_ci} 8221cb0ef41Sopenharmony_ci 8231cb0ef41Sopenharmony_civoid Worker::LoopIdleTime(const FunctionCallbackInfo<Value>& args) { 8241cb0ef41Sopenharmony_ci Worker* w; 8251cb0ef41Sopenharmony_ci ASSIGN_OR_RETURN_UNWRAP(&w, args.This()); 8261cb0ef41Sopenharmony_ci 8271cb0ef41Sopenharmony_ci Mutex::ScopedLock lock(w->mutex_); 8281cb0ef41Sopenharmony_ci // Using w->is_stopped() here leads to a deadlock, and checking is_stopped() 8291cb0ef41Sopenharmony_ci // before locking the mutex is a race condition. So manually do the same 8301cb0ef41Sopenharmony_ci // check. 8311cb0ef41Sopenharmony_ci if (w->stopped_ || w->env_ == nullptr) 8321cb0ef41Sopenharmony_ci return args.GetReturnValue().Set(-1); 8331cb0ef41Sopenharmony_ci 8341cb0ef41Sopenharmony_ci uint64_t idle_time = uv_metrics_idle_time(w->env_->event_loop()); 8351cb0ef41Sopenharmony_ci args.GetReturnValue().Set(1.0 * idle_time / 1e6); 8361cb0ef41Sopenharmony_ci} 8371cb0ef41Sopenharmony_ci 8381cb0ef41Sopenharmony_civoid Worker::LoopStartTime(const FunctionCallbackInfo<Value>& args) { 8391cb0ef41Sopenharmony_ci Worker* w; 8401cb0ef41Sopenharmony_ci ASSIGN_OR_RETURN_UNWRAP(&w, args.This()); 8411cb0ef41Sopenharmony_ci 8421cb0ef41Sopenharmony_ci Mutex::ScopedLock lock(w->mutex_); 8431cb0ef41Sopenharmony_ci // Using w->is_stopped() here leads to a deadlock, and checking is_stopped() 8441cb0ef41Sopenharmony_ci // before locking the mutex is a race condition. So manually do the same 8451cb0ef41Sopenharmony_ci // check. 8461cb0ef41Sopenharmony_ci if (w->stopped_ || w->env_ == nullptr) 8471cb0ef41Sopenharmony_ci return args.GetReturnValue().Set(-1); 8481cb0ef41Sopenharmony_ci 8491cb0ef41Sopenharmony_ci double loop_start_time = w->env_->performance_state()->milestones[ 8501cb0ef41Sopenharmony_ci node::performance::NODE_PERFORMANCE_MILESTONE_LOOP_START]; 8511cb0ef41Sopenharmony_ci CHECK_GE(loop_start_time, 0); 8521cb0ef41Sopenharmony_ci args.GetReturnValue().Set( 8531cb0ef41Sopenharmony_ci (loop_start_time - node::performance::timeOrigin) / 1e6); 8541cb0ef41Sopenharmony_ci} 8551cb0ef41Sopenharmony_ci 8561cb0ef41Sopenharmony_cinamespace { 8571cb0ef41Sopenharmony_ci 8581cb0ef41Sopenharmony_ci// Return the MessagePort that is global for this Environment and communicates 8591cb0ef41Sopenharmony_ci// with the internal [kPort] port of the JS Worker class in the parent thread. 8601cb0ef41Sopenharmony_civoid GetEnvMessagePort(const FunctionCallbackInfo<Value>& args) { 8611cb0ef41Sopenharmony_ci Environment* env = Environment::GetCurrent(args); 8621cb0ef41Sopenharmony_ci Local<Object> port = env->message_port(); 8631cb0ef41Sopenharmony_ci CHECK_IMPLIES(!env->is_main_thread(), !port.IsEmpty()); 8641cb0ef41Sopenharmony_ci if (!port.IsEmpty()) { 8651cb0ef41Sopenharmony_ci CHECK_EQ(port->GetCreationContext().ToLocalChecked()->GetIsolate(), 8661cb0ef41Sopenharmony_ci args.GetIsolate()); 8671cb0ef41Sopenharmony_ci args.GetReturnValue().Set(port); 8681cb0ef41Sopenharmony_ci } 8691cb0ef41Sopenharmony_ci} 8701cb0ef41Sopenharmony_ci 8711cb0ef41Sopenharmony_civoid InitWorker(Local<Object> target, 8721cb0ef41Sopenharmony_ci Local<Value> unused, 8731cb0ef41Sopenharmony_ci Local<Context> context, 8741cb0ef41Sopenharmony_ci void* priv) { 8751cb0ef41Sopenharmony_ci Environment* env = Environment::GetCurrent(context); 8761cb0ef41Sopenharmony_ci Isolate* isolate = env->isolate(); 8771cb0ef41Sopenharmony_ci 8781cb0ef41Sopenharmony_ci { 8791cb0ef41Sopenharmony_ci Local<FunctionTemplate> w = NewFunctionTemplate(isolate, Worker::New); 8801cb0ef41Sopenharmony_ci 8811cb0ef41Sopenharmony_ci w->InstanceTemplate()->SetInternalFieldCount( 8821cb0ef41Sopenharmony_ci Worker::kInternalFieldCount); 8831cb0ef41Sopenharmony_ci w->Inherit(AsyncWrap::GetConstructorTemplate(env)); 8841cb0ef41Sopenharmony_ci 8851cb0ef41Sopenharmony_ci SetProtoMethod(isolate, w, "startThread", Worker::StartThread); 8861cb0ef41Sopenharmony_ci SetProtoMethod(isolate, w, "stopThread", Worker::StopThread); 8871cb0ef41Sopenharmony_ci SetProtoMethod(isolate, w, "hasRef", Worker::HasRef); 8881cb0ef41Sopenharmony_ci SetProtoMethod(isolate, w, "ref", Worker::Ref); 8891cb0ef41Sopenharmony_ci SetProtoMethod(isolate, w, "unref", Worker::Unref); 8901cb0ef41Sopenharmony_ci SetProtoMethod(isolate, w, "getResourceLimits", Worker::GetResourceLimits); 8911cb0ef41Sopenharmony_ci SetProtoMethod(isolate, w, "takeHeapSnapshot", Worker::TakeHeapSnapshot); 8921cb0ef41Sopenharmony_ci SetProtoMethod(isolate, w, "loopIdleTime", Worker::LoopIdleTime); 8931cb0ef41Sopenharmony_ci SetProtoMethod(isolate, w, "loopStartTime", Worker::LoopStartTime); 8941cb0ef41Sopenharmony_ci 8951cb0ef41Sopenharmony_ci SetConstructorFunction(context, target, "Worker", w); 8961cb0ef41Sopenharmony_ci } 8971cb0ef41Sopenharmony_ci 8981cb0ef41Sopenharmony_ci { 8991cb0ef41Sopenharmony_ci Local<FunctionTemplate> wst = NewFunctionTemplate(isolate, nullptr); 9001cb0ef41Sopenharmony_ci 9011cb0ef41Sopenharmony_ci wst->InstanceTemplate()->SetInternalFieldCount( 9021cb0ef41Sopenharmony_ci WorkerHeapSnapshotTaker::kInternalFieldCount); 9031cb0ef41Sopenharmony_ci wst->Inherit(AsyncWrap::GetConstructorTemplate(env)); 9041cb0ef41Sopenharmony_ci 9051cb0ef41Sopenharmony_ci Local<String> wst_string = 9061cb0ef41Sopenharmony_ci FIXED_ONE_BYTE_STRING(isolate, "WorkerHeapSnapshotTaker"); 9071cb0ef41Sopenharmony_ci wst->SetClassName(wst_string); 9081cb0ef41Sopenharmony_ci env->set_worker_heap_snapshot_taker_template(wst->InstanceTemplate()); 9091cb0ef41Sopenharmony_ci } 9101cb0ef41Sopenharmony_ci 9111cb0ef41Sopenharmony_ci SetMethod(context, target, "getEnvMessagePort", GetEnvMessagePort); 9121cb0ef41Sopenharmony_ci 9131cb0ef41Sopenharmony_ci target 9141cb0ef41Sopenharmony_ci ->Set(env->context(), 9151cb0ef41Sopenharmony_ci env->thread_id_string(), 9161cb0ef41Sopenharmony_ci Number::New(isolate, static_cast<double>(env->thread_id()))) 9171cb0ef41Sopenharmony_ci .Check(); 9181cb0ef41Sopenharmony_ci 9191cb0ef41Sopenharmony_ci target 9201cb0ef41Sopenharmony_ci ->Set(env->context(), 9211cb0ef41Sopenharmony_ci FIXED_ONE_BYTE_STRING(isolate, "isMainThread"), 9221cb0ef41Sopenharmony_ci Boolean::New(isolate, env->is_main_thread())) 9231cb0ef41Sopenharmony_ci .Check(); 9241cb0ef41Sopenharmony_ci 9251cb0ef41Sopenharmony_ci target 9261cb0ef41Sopenharmony_ci ->Set(env->context(), 9271cb0ef41Sopenharmony_ci FIXED_ONE_BYTE_STRING(isolate, "ownsProcessState"), 9281cb0ef41Sopenharmony_ci Boolean::New(isolate, env->owns_process_state())) 9291cb0ef41Sopenharmony_ci .Check(); 9301cb0ef41Sopenharmony_ci 9311cb0ef41Sopenharmony_ci if (!env->is_main_thread()) { 9321cb0ef41Sopenharmony_ci target 9331cb0ef41Sopenharmony_ci ->Set(env->context(), 9341cb0ef41Sopenharmony_ci FIXED_ONE_BYTE_STRING(isolate, "resourceLimits"), 9351cb0ef41Sopenharmony_ci env->worker_context()->GetResourceLimits(isolate)) 9361cb0ef41Sopenharmony_ci .Check(); 9371cb0ef41Sopenharmony_ci } 9381cb0ef41Sopenharmony_ci 9391cb0ef41Sopenharmony_ci NODE_DEFINE_CONSTANT(target, kMaxYoungGenerationSizeMb); 9401cb0ef41Sopenharmony_ci NODE_DEFINE_CONSTANT(target, kMaxOldGenerationSizeMb); 9411cb0ef41Sopenharmony_ci NODE_DEFINE_CONSTANT(target, kCodeRangeSizeMb); 9421cb0ef41Sopenharmony_ci NODE_DEFINE_CONSTANT(target, kStackSizeMb); 9431cb0ef41Sopenharmony_ci NODE_DEFINE_CONSTANT(target, kTotalResourceLimitCount); 9441cb0ef41Sopenharmony_ci} 9451cb0ef41Sopenharmony_ci 9461cb0ef41Sopenharmony_civoid RegisterExternalReferences(ExternalReferenceRegistry* registry) { 9471cb0ef41Sopenharmony_ci registry->Register(GetEnvMessagePort); 9481cb0ef41Sopenharmony_ci registry->Register(Worker::New); 9491cb0ef41Sopenharmony_ci registry->Register(Worker::StartThread); 9501cb0ef41Sopenharmony_ci registry->Register(Worker::StopThread); 9511cb0ef41Sopenharmony_ci registry->Register(Worker::HasRef); 9521cb0ef41Sopenharmony_ci registry->Register(Worker::Ref); 9531cb0ef41Sopenharmony_ci registry->Register(Worker::Unref); 9541cb0ef41Sopenharmony_ci registry->Register(Worker::GetResourceLimits); 9551cb0ef41Sopenharmony_ci registry->Register(Worker::TakeHeapSnapshot); 9561cb0ef41Sopenharmony_ci registry->Register(Worker::LoopIdleTime); 9571cb0ef41Sopenharmony_ci registry->Register(Worker::LoopStartTime); 9581cb0ef41Sopenharmony_ci} 9591cb0ef41Sopenharmony_ci 9601cb0ef41Sopenharmony_ci} // anonymous namespace 9611cb0ef41Sopenharmony_ci} // namespace worker 9621cb0ef41Sopenharmony_ci} // namespace node 9631cb0ef41Sopenharmony_ci 9641cb0ef41Sopenharmony_ciNODE_BINDING_CONTEXT_AWARE_INTERNAL(worker, node::worker::InitWorker) 9651cb0ef41Sopenharmony_ciNODE_BINDING_EXTERNAL_REFERENCE(worker, 9661cb0ef41Sopenharmony_ci node::worker::RegisterExternalReferences) 967