GCC Code Coverage Report
Directory: ../ Exec Total Coverage
File: /home/iojs/build/workspace/node-test-commit-linux-coverage-daily/nodes/benchmark/out/../src/node_worker.cc Lines: 312 316 98.7 %
Date: 2019-03-02 22:23:06 Branches: 127 166 76.5 %

Line Branch Exec Source
1
#include "node_worker.h"
2
#include "debug_utils.h"
3
#include "node_errors.h"
4
#include "node_buffer.h"
5
#include "node_perf.h"
6
#include "util.h"
7
#include "util-inl.h"
8
#include "async_wrap.h"
9
#include "async_wrap-inl.h"
10
11
#if NODE_USE_V8_PLATFORM && HAVE_INSPECTOR
12
#include "inspector/worker_inspector.h"  // ParentInspectorHandle
13
#endif
14
15
#include <string>
16
#include <vector>
17
18
using node::options_parser::kDisallowedInEnvironment;
19
using v8::ArrayBuffer;
20
using v8::Boolean;
21
using v8::Context;
22
using v8::Function;
23
using v8::FunctionCallbackInfo;
24
using v8::FunctionTemplate;
25
using v8::HandleScope;
26
using v8::Integer;
27
using v8::Isolate;
28
using v8::Local;
29
using v8::Locker;
30
using v8::Number;
31
using v8::Object;
32
using v8::SealHandleScope;
33
using v8::String;
34
using v8::Value;
35
36
namespace node {
37
namespace worker {
38
39
namespace {
40
41
#if NODE_USE_V8_PLATFORM && HAVE_INSPECTOR
42
172
void StartWorkerInspector(
43
    Environment* child,
44
    std::unique_ptr<inspector::ParentInspectorHandle> parent_handle,
45
    const std::string& url) {
46
172
  child->inspector_agent()->SetParentHandle(std::move(parent_handle));
47
  child->inspector_agent()->Start(url,
48
344
                                  child->options()->debug_options(),
49
                                  child->inspector_host_port(),
50
516
                                  false);
51
172
}
52
53
172
void WaitForWorkerInspectorToStop(Environment* child) {
54
172
  child->inspector_agent()->WaitForDisconnect();
55
172
  child->inspector_agent()->Stop();
56
172
}
57
#endif
58
59
}  // anonymous namespace
60
61
348
void AsyncRequest::Install(Environment* env, void* data, uv_async_cb target) {
62
348
  Mutex::ScopedLock lock(mutex_);
63
348
  env_ = env;
64
348
  async_ = new uv_async_t;
65
348
  if (data != nullptr) async_->data = data;
66
348
  CHECK_EQ(uv_async_init(env_->event_loop(), async_, target), 0);
67
348
}
68
69
346
void AsyncRequest::Uninstall() {
70
346
  Mutex::ScopedLock lock(mutex_);
71
346
  if (async_ != nullptr)
72
670
    env_->CloseHandle(async_, [](uv_async_t* async) { delete async; });
73
346
}
74
75
243
void AsyncRequest::Stop() {
76
243
  Mutex::ScopedLock lock(mutex_);
77
243
  stop_ = true;
78
243
  if (async_ != nullptr) uv_async_send(async_);
79
243
}
80
81
349
void AsyncRequest::SetStopped(bool flag) {
82
349
  Mutex::ScopedLock lock(mutex_);
83
349
  stop_ = flag;
84
349
}
85
86
22571
bool AsyncRequest::IsStopped() const {
87
22571
  Mutex::ScopedLock lock(mutex_);
88
22572
  return stop_;
89
}
90
91
176
uv_async_t* AsyncRequest::GetHandle() {
92
176
  Mutex::ScopedLock lock(mutex_);
93
176
  return async_;
94
}
95
96
8
void AsyncRequest::MemoryInfo(MemoryTracker* tracker) const {
97
8
  Mutex::ScopedLock lock(mutex_);
98
8
  if (async_ != nullptr) tracker->TrackField("async_request", *async_);
99
8
}
100
101
177
Worker::Worker(Environment* env,
102
               Local<Object> wrap,
103
               const std::string& url,
104
               std::shared_ptr<PerIsolateOptions> per_isolate_opts,
105
               std::vector<std::string>&& exec_argv)
106
    : AsyncWrap(env, wrap, AsyncWrap::PROVIDER_WORKER),
107
      url_(url),
108
      per_isolate_opts_(per_isolate_opts),
109
      exec_argv_(exec_argv),
110
177
      platform_(env->isolate_data()->platform()),
111
177
      profiler_idle_notifier_started_(env->profiler_idle_notifier_started()),
112
531
      thread_id_(Environment::AllocateThreadId()) {
113
177
  Debug(this, "Creating new worker instance with thread id %llu", thread_id_);
114
115
  // Set up everything that needs to be set up in the parent environment.
116
177
  parent_port_ = MessagePort::New(env, env->context());
117
177
  if (parent_port_ == nullptr) {
118
    // This can happen e.g. because execution is terminating.
119
177
    return;
120
  }
121
122
177
  child_port_data_.reset(new MessagePortData(nullptr));
123
177
  MessagePort::Entangle(parent_port_, child_port_data_.get());
124
125
177
  object()->Set(env->context(),
126
                env->message_port_string(),
127
1062
                parent_port_->object()).FromJust();
128
129
177
  object()->Set(env->context(),
130
                env->thread_id_string(),
131
1062
                Number::New(env->isolate(), static_cast<double>(thread_id_)))
132
354
      .FromJust();
133
134
#if NODE_USE_V8_PLATFORM && HAVE_INSPECTOR
135
354
  inspector_parent_handle_ =
136
177
      env->inspector_agent()->GetParentHandle(thread_id_, url);
137
#endif
138
139
177
  Debug(this, "Preparation for worker %llu finished", thread_id_);
140
}
141
142
20857
bool Worker::is_stopped() const {
143
20857
  return thread_stopper_.IsStopped();
144
}
145
146
// This class contains data that is only relevant to the child thread itself,
147
// and only while it is running.
148
// (Eventually, the Environment instance should probably also be moved here.)
149
class WorkerThreadData {
150
 public:
151
176
  explicit WorkerThreadData(Worker* w)
152
    : w_(w),
153
176
      array_buffer_allocator_(CreateArrayBufferAllocator()) {
154
176
    CHECK_EQ(uv_loop_init(&loop_), 0);
155
156
176
    Isolate* isolate = NewIsolate(array_buffer_allocator_.get(), &loop_);
157
176
    CHECK_NOT_NULL(isolate);
158
159
    {
160
176
      Locker locker(isolate);
161
352
      Isolate::Scope isolate_scope(isolate);
162
176
      isolate->SetStackLimit(w_->stack_base_);
163
164
352
      HandleScope handle_scope(isolate);
165
      isolate_data_.reset(CreateIsolateData(isolate,
166
                                            &loop_,
167
                                            w_->platform_,
168
176
                                            array_buffer_allocator_.get()));
169
176
      CHECK(isolate_data_);
170
176
      if (w_->per_isolate_opts_)
171
182
        isolate_data_->set_options(std::move(w_->per_isolate_opts_));
172
    }
173
174
176
    Mutex::ScopedLock lock(w_->mutex_);
175
176
    w_->isolate_ = isolate;
176
176
  }
177
178
352
  ~WorkerThreadData() {
179
176
    Debug(w_, "Worker %llu dispose isolate", w_->thread_id_);
180
    Isolate* isolate;
181
    {
182
176
      Mutex::ScopedLock lock(w_->mutex_);
183
175
      isolate = w_->isolate_;
184
175
      w_->isolate_ = nullptr;
185
    }
186
187
175
    w_->platform_->CancelPendingDelayedTasks(isolate);
188
189
176
    isolate_data_.reset();
190
176
    w_->platform_->UnregisterIsolate(isolate);
191
192
176
    isolate->Dispose();
193
194
    // Need to run the loop twice more to close the platform's uv_async_t
195
    // TODO(addaleax): It would be better for the platform itself to provide
196
    // some kind of notification when it has fully cleaned up.
197
176
    uv_run(&loop_, UV_RUN_ONCE);
198
176
    uv_run(&loop_, UV_RUN_ONCE);
199
200
176
    CheckedUvLoopClose(&loop_);
201
176
  }
202
203
 private:
204
  Worker* const w_;
205
  uv_loop_t loop_;
206
  DeleteFnPtr<ArrayBufferAllocator, FreeArrayBufferAllocator>
207
    array_buffer_allocator_;
208
  DeleteFnPtr<IsolateData, FreeIsolateData> isolate_data_;
209
210
  friend class Worker;
211
};
212
213
176
void Worker::Run() {
214
176
  std::string name = "WorkerThread ";
215
176
  name += std::to_string(thread_id_);
216

354
  TRACE_EVENT_METADATA1(
217
      "__metadata", "thread_name", "name",
218
      TRACE_STR_COPY(name.c_str()));
219
176
  CHECK_NOT_NULL(platform_);
220
221
176
  Debug(this, "Creating isolate for worker with id %llu", thread_id_);
222
223
341
  WorkerThreadData data(this);
224
225
176
  Debug(this, "Starting worker with id %llu", thread_id_);
226
  {
227
176
    Locker locker(isolate_);
228
341
    Isolate::Scope isolate_scope(isolate_);
229
341
    SealHandleScope outer_seal(isolate_);
230
176
    bool inspector_started = false;
231
232
341
    DeleteFnPtr<Environment, FreeEnvironment> env_;
233
176
    OnScopeLeave cleanup_env([&]() {
234
352
      if (!env_) return;
235
173
      env_->set_can_call_into_js(false);
236
      Isolate::DisallowJavascriptExecutionScope disallow_js(isolate_,
237
173
          Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE);
238
239
      // Grab the parent-to-child channel and render is unusable.
240
      MessagePort* child_port;
241
      {
242
173
        Mutex::ScopedLock lock(mutex_);
243
173
        child_port = child_port_;
244
173
        child_port_ = nullptr;
245
      }
246
247
      {
248
173
        Context::Scope context_scope(env_->context());
249
173
        if (child_port != nullptr)
250
344
          child_port->Close();
251
173
        thread_stopper_.Uninstall();
252
173
        thread_stopper_.SetStopped(true);
253
173
        env_->stop_sub_worker_contexts();
254
173
        env_->RunCleanup();
255
173
        RunAtExit(env_.get());
256
#if NODE_USE_V8_PLATFORM && HAVE_INSPECTOR
257
173
        if (inspector_started)
258
172
          WaitForWorkerInspectorToStop(env_.get());
259
#endif
260
261
        // This call needs to be made while the `Environment` is still alive
262
        // because we assume that it is available for async tracking in the
263
        // NodePlatform implementation.
264
173
        platform_->DrainTasks(isolate_);
265
      }
266
514
    });
267
268
176
    if (thread_stopper_.IsStopped()) return;
269
    {
270
175
      HandleScope handle_scope(isolate_);
271
175
      Local<Context> context = NewContext(isolate_);
272
273
175
      if (thread_stopper_.IsStopped()) return;
274
173
      CHECK(!context.IsEmpty());
275
164
      Context::Scope context_scope(context);
276
      {
277
        // TODO(addaleax): Use CreateEnvironment(), or generally another
278
        // public API.
279
        env_.reset(new Environment(data.isolate_data_.get(),
280
                                   context,
281
                                   Environment::kNoFlags,
282
173
                                   thread_id_));
283
173
        CHECK_NOT_NULL(env_);
284
173
        env_->set_abort_on_uncaught_exception(false);
285
173
        env_->set_worker_context(this);
286
287
173
        env_->Start(profiler_idle_notifier_started_);
288
        env_->ProcessCliArgs(std::vector<std::string>{},
289
173
                             std::move(exec_argv_));
290
      }
291
292
173
      Debug(this, "Created Environment for worker with id %llu", thread_id_);
293
294
173
      if (is_stopped()) return;
295
398
      thread_stopper_.Install(env_.get(), env_.get(), [](uv_async_t* handle) {
296
27
        Environment* env_ = static_cast<Environment*>(handle->data);
297
27
        uv_stop(env_->event_loop());
298
570
      });
299
172
      uv_unref(reinterpret_cast<uv_handle_t*>(thread_stopper_.GetHandle()));
300
301
172
      Debug(this, "Created Environment for worker with id %llu", thread_id_);
302
172
      if (thread_stopper_.IsStopped()) return;
303
      {
304
172
        HandleScope handle_scope(isolate_);
305
344
        Mutex::ScopedLock lock(mutex_);
306
        // Set up the message channel for receiving messages in the child.
307
        child_port_ = MessagePort::New(env_.get(),
308
                                       env_->context(),
309
172
                                       std::move(child_port_data_));
310
        // MessagePort::New() may return nullptr if execution is terminated
311
        // within it.
312
172
        if (child_port_ != nullptr)
313
172
          env_->set_message_port(child_port_->object(isolate_));
314
315
344
        Debug(this, "Created message port for worker %llu", thread_id_);
316
      }
317
318
172
      if (thread_stopper_.IsStopped()) return;
319
      {
320
#if NODE_USE_V8_PLATFORM && HAVE_INSPECTOR
321
        StartWorkerInspector(env_.get(),
322
172
                             std::move(inspector_parent_handle_),
323
344
                             url_);
324
#endif
325
172
        inspector_started = true;
326
327
172
        HandleScope handle_scope(isolate_);
328
344
        Environment::AsyncCallbackScope callback_scope(env_.get());
329
172
        env_->async_hooks()->push_async_ids(1, 0);
330
344
        if (!RunBootstrapping(env_.get()).IsEmpty()) {
331
165
          USE(StartExecution(env_.get(), "internal/main/worker_thread"));
332
        }
333
334
172
        env_->async_hooks()->pop_async_id(1);
335
336
344
        Debug(this, "Loaded environment for worker %llu", thread_id_);
337
      }
338
339
172
      if (thread_stopper_.IsStopped()) return;
340
      {
341
165
        SealHandleScope seal(isolate_);
342
        bool more;
343
        env_->performance_state()->Mark(
344
165
            node::performance::NODE_PERFORMANCE_MILESTONE_LOOP_START);
345
109
        do {
346
165
          if (thread_stopper_.IsStopped()) break;
347
165
          uv_run(&data.loop_, UV_RUN_DEFAULT);
348
165
          if (thread_stopper_.IsStopped()) break;
349
350
109
          platform_->DrainTasks(isolate_);
351
352
109
          more = uv_loop_alive(&data.loop_);
353

109
          if (more && !thread_stopper_.IsStopped()) continue;
354
355
109
          EmitBeforeExit(env_.get());
356
357
          // Emit `beforeExit` if the loop became alive either after emitting
358
          // event, or after running some callbacks.
359
109
          more = uv_loop_alive(&data.loop_);
360
        } while (more == true);
361
        env_->performance_state()->Mark(
362
165
            node::performance::NODE_PERFORMANCE_MILESTONE_LOOP_EXIT);
363
165
      }
364
    }
365
366
    {
367
      int exit_code;
368
165
      bool stopped = thread_stopper_.IsStopped();
369
165
      if (!stopped)
370
109
        exit_code = EmitExit(env_.get());
371
165
      Mutex::ScopedLock lock(mutex_);
372

165
      if (exit_code_ == 0 && !stopped)
373
109
        exit_code_ = exit_code;
374
375
      Debug(this, "Exiting thread for worker %llu with exit code %d",
376
330
            thread_id_, exit_code_);
377
165
    }
378
  }
379
380
330
  Debug(this, "Worker %llu thread stops", thread_id_);
381
}
382
383
330
void Worker::JoinThread() {
384
330
  if (thread_joined_)
385
481
    return;
386
176
  CHECK_EQ(uv_thread_join(&tid_), 0);
387
176
  thread_joined_ = true;
388
389
176
  env()->remove_sub_worker_context(this);
390
176
  OnThreadStopped();
391
173
  on_thread_finished_.Uninstall();
392
}
393
394
176
void Worker::OnThreadStopped() {
395
  {
396
176
    HandleScope handle_scope(env()->isolate());
397
176
    Context::Scope context_scope(env()->context());
398
399
    // Reset the parent port as we're closing it now anyway.
400
176
    object()->Set(env()->context(),
401
                  env()->message_port_string(),
402
1056
                  Undefined(env()->isolate())).FromJust();
403
404
176
    Local<Value> code = Integer::New(env()->isolate(), exit_code_);
405
349
    MakeCallback(env()->onexit_string(), 1, &code);
406
  }
407
408
  // JoinThread() cleared all libuv handles bound to this Worker,
409
  // the C++ object is no longer needed for anything now.
410
173
  MakeWeak();
411
173
}
412
413
462
Worker::~Worker() {
414
154
  Mutex::ScopedLock lock(mutex_);
415
154
  JoinThread();
416
417
154
  CHECK(thread_stopper_.IsStopped());
418
154
  CHECK(thread_joined_);
419
420
  // This has most likely already happened within the worker thread -- this
421
  // is just in case Worker creation failed early.
422
423
308
  Debug(this, "Worker %llu destroyed", thread_id_);
424
308
}
425
426
180
void Worker::New(const FunctionCallbackInfo<Value>& args) {
427
180
  Environment* env = Environment::GetCurrent(args);
428
429
180
  CHECK(args.IsConstructCall());
430
431
180
  if (env->isolate_data()->platform() == nullptr) {
432
    THROW_ERR_MISSING_PLATFORM_FOR_WORKER(env);
433
    return;
434
  }
435
436
180
  std::string url;
437
357
  std::shared_ptr<PerIsolateOptions> per_isolate_opts = nullptr;
438
439
357
  std::vector<std::string> exec_argv_out;
440
180
  bool has_explicit_exec_argv = false;
441
442
  // Argument might be a string or URL
443


900
  if (args.Length() > 0 && !args[0]->IsNullOrUndefined()) {
444
    Utf8Value value(
445
        args.GetIsolate(),
446
232
        args[0]->ToString(env->context()).FromMaybe(v8::Local<v8::String>()));
447
58
    url.append(value.out(), value.length());
448
449


232
    if (args.Length() > 1 && args[1]->IsArray()) {
450
18
      v8::Local<v8::Array> array = args[1].As<v8::Array>();
451
      // The first argument is reserved for program name, but we don't need it
452
      // in workers.
453
9
      has_explicit_exec_argv = true;
454
9
      std::vector<std::string> exec_argv = {""};
455
9
      uint32_t length = array->Length();
456
38
      for (uint32_t i = 0; i < length; i++) {
457
        v8::Local<v8::Value> arg;
458
30
        if (!array->Get(env->context(), i).ToLocal(&arg)) {
459
          return;
460
        }
461
        v8::MaybeLocal<v8::String> arg_v8_string =
462
20
            arg->ToString(env->context());
463
10
        if (arg_v8_string.IsEmpty()) {
464
          return;
465
        }
466
        Utf8Value arg_utf8_value(
467
            args.GetIsolate(),
468
10
            arg_v8_string.FromMaybe(v8::Local<v8::String>()));
469
20
        std::string arg_string(arg_utf8_value.out(), arg_utf8_value.length());
470
10
        exec_argv.push_back(arg_string);
471
10
      }
472
473
15
      std::vector<std::string> invalid_args{};
474
15
      std::vector<std::string> errors{};
475
9
      per_isolate_opts.reset(new PerIsolateOptions());
476
477
      // Using invalid_args as the v8_args argument as it stores unknown
478
      // options for the per isolate parser.
479
      options_parser::PerIsolateOptionsParser::instance.Parse(
480
          &exec_argv,
481
          &exec_argv_out,
482
          &invalid_args,
483
          per_isolate_opts.get(),
484
          kDisallowedInEnvironment,
485
9
          &errors);
486
487
      // The first argument is program name.
488
9
      invalid_args.erase(invalid_args.begin());
489

9
      if (errors.size() > 0 || invalid_args.size() > 0) {
490
        v8::Local<v8::Value> value =
491
            ToV8Value(env->context(),
492
3
                      errors.size() > 0 ? errors : invalid_args)
493
6
                .ToLocalChecked();
494
        Local<String> key =
495
3
            FIXED_ONE_BYTE_STRING(env->isolate(), "invalidExecArgv");
496
12
        args.This()->Set(env->context(), key, value).FromJust();
497
3
        return;
498
6
      }
499
55
    }
500
  }
501
177
  if (!has_explicit_exec_argv)
502
171
    exec_argv_out = env->exec_argv();
503
354
  new Worker(env, args.This(), url, per_isolate_opts, std::move(exec_argv_out));
504
}
505
506
176
void Worker::StartThread(const FunctionCallbackInfo<Value>& args) {
507
  Worker* w;
508
352
  ASSIGN_OR_RETURN_UNWRAP(&w, args.This());
509
176
  Mutex::ScopedLock lock(w->mutex_);
510
511
176
  w->env()->add_sub_worker_context(w);
512
176
  w->thread_joined_ = false;
513
176
  w->thread_stopper_.SetStopped(false);
514
515
436
  w->on_thread_finished_.Install(w->env(), w, [](uv_async_t* handle) {
516
130
    Worker* w_ = static_cast<Worker*>(handle->data);
517
130
    CHECK(w_->thread_stopper_.IsStopped());
518
130
    w_->parent_port_ = nullptr;
519
130
    w_->JoinThread();
520
610
  });
521
522
  uv_thread_options_t thread_options;
523
176
  thread_options.flags = UV_THREAD_HAS_STACK_SIZE;
524
176
  thread_options.stack_size = kStackSize;
525
704
  CHECK_EQ(uv_thread_create_ex(&w->tid_, &thread_options, [](void* arg) {
526
    Worker* w = static_cast<Worker*>(arg);
527
    const uintptr_t stack_top = reinterpret_cast<uintptr_t>(&arg);
528
529
    // Leave a few kilobytes just to make sure we're within limits and have
530
    // some space to do work in C++ land.
531
    w->stack_base_ = stack_top - (kStackSize - kStackBufferSize);
532
533
    w->Run();
534
535
    Mutex::ScopedLock lock(w->mutex_);
536
    w->on_thread_finished_.Stop();
537
176
  }, static_cast<void*>(w)), 0);
538
}
539
540
23
void Worker::StopThread(const FunctionCallbackInfo<Value>& args) {
541
  Worker* w;
542
46
  ASSIGN_OR_RETURN_UNWRAP(&w, args.This());
543
544
23
  Debug(w, "Worker %llu is getting stopped by parent", w->thread_id_);
545
23
  w->Exit(1);
546
23
  w->JoinThread();
547
}
548
549
1
void Worker::Ref(const FunctionCallbackInfo<Value>& args) {
550
  Worker* w;
551
2
  ASSIGN_OR_RETURN_UNWRAP(&w, args.This());
552
1
  uv_ref(reinterpret_cast<uv_handle_t*>(w->on_thread_finished_.GetHandle()));
553
}
554
555
3
void Worker::Unref(const FunctionCallbackInfo<Value>& args) {
556
  Worker* w;
557
6
  ASSIGN_OR_RETURN_UNWRAP(&w, args.This());
558
3
  uv_unref(reinterpret_cast<uv_handle_t*>(w->on_thread_finished_.GetHandle()));
559
}
560
561
68
void Worker::Exit(int code) {
562
68
  Mutex::ScopedLock lock(mutex_);
563
564
68
  Debug(this, "Worker %llu called Exit(%d)", thread_id_, code);
565
68
  if (!thread_stopper_.IsStopped()) {
566
67
    exit_code_ = code;
567
67
    Debug(this, "Received StopEventLoop request");
568
67
    thread_stopper_.Stop();
569
67
    if (isolate_ != nullptr)
570
66
      isolate_->TerminateExecution();
571
68
  }
572
68
}
573
574
namespace {
575
576
// Return the MessagePort that is global for this Environment and communicates
577
// with the internal [kPort] port of the JS Worker class in the parent thread.
578
330
void GetEnvMessagePort(const FunctionCallbackInfo<Value>& args) {
579
330
  Environment* env = Environment::GetCurrent(args);
580
330
  Local<Object> port = env->message_port();
581
330
  if (!port.IsEmpty()) {
582
990
    CHECK_EQ(port->CreationContext()->GetIsolate(), args.GetIsolate());
583
660
    args.GetReturnValue().Set(port);
584
  }
585
330
}
586
587
4404
void InitWorker(Local<Object> target,
588
                Local<Value> unused,
589
                Local<Context> context,
590
                void* priv) {
591
4404
  Environment* env = Environment::GetCurrent(context);
592
593
  {
594
4404
    Local<FunctionTemplate> w = env->NewFunctionTemplate(Worker::New);
595
596
8808
    w->InstanceTemplate()->SetInternalFieldCount(1);
597
8808
    w->Inherit(AsyncWrap::GetConstructorTemplate(env));
598
599
4404
    env->SetProtoMethod(w, "startThread", Worker::StartThread);
600
4404
    env->SetProtoMethod(w, "stopThread", Worker::StopThread);
601
4404
    env->SetProtoMethod(w, "ref", Worker::Ref);
602
4404
    env->SetProtoMethod(w, "unref", Worker::Unref);
603
604
    Local<String> workerString =
605
4404
        FIXED_ONE_BYTE_STRING(env->isolate(), "Worker");
606
4404
    w->SetClassName(workerString);
607
    target->Set(env->context(),
608
                workerString,
609
22020
                w->GetFunction(env->context()).ToLocalChecked()).FromJust();
610
  }
611
612
4404
  env->SetMethod(target, "getEnvMessagePort", GetEnvMessagePort);
613
614
  target
615
      ->Set(env->context(),
616
            env->thread_id_string(),
617
22020
            Number::New(env->isolate(), static_cast<double>(env->thread_id())))
618
8808
      .FromJust();
619
620
  target
621
      ->Set(env->context(),
622
            FIXED_ONE_BYTE_STRING(env->isolate(), "isMainThread"),
623
22020
            Boolean::New(env->isolate(), env->is_main_thread()))
624
8808
      .FromJust();
625
626
  target
627
      ->Set(env->context(),
628
            FIXED_ONE_BYTE_STRING(env->isolate(), "ownsProcessState"),
629
22020
            Boolean::New(env->isolate(), env->owns_process_state()))
630
8808
      .FromJust();
631
4404
}
632
633
}  // anonymous namespace
634
635
}  // namespace worker
636
}  // namespace node
637
638
4292
NODE_MODULE_CONTEXT_AWARE_INTERNAL(worker, node::worker::InitWorker)