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: 303 308 98.4 %
Date: 2019-10-08 22:34:21 Branches: 123 172 71.5 %

Line Branch Exec Source
1
#include "node_worker.h"
2
#include "debug_utils.h"
3
#include "memory_tracker-inl.h"
4
#include "node_errors.h"
5
#include "node_buffer.h"
6
#include "node_options-inl.h"
7
#include "node_perf.h"
8
#include "util-inl.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 <memory>
16
#include <string>
17
#include <vector>
18
19
using node::options_parser::kDisallowedInEnvironment;
20
using v8::Array;
21
using v8::ArrayBuffer;
22
using v8::Boolean;
23
using v8::Context;
24
using v8::Function;
25
using v8::FunctionCallbackInfo;
26
using v8::FunctionTemplate;
27
using v8::HandleScope;
28
using v8::Integer;
29
using v8::Isolate;
30
using v8::Local;
31
using v8::Locker;
32
using v8::MaybeLocal;
33
using v8::Number;
34
using v8::Object;
35
using v8::SealHandleScope;
36
using v8::String;
37
using v8::Value;
38
39
namespace node {
40
namespace worker {
41
42
namespace {
43
44
#if NODE_USE_V8_PLATFORM && HAVE_INSPECTOR
45
210
void WaitForWorkerInspectorToStop(Environment* child) {
46
210
  child->inspector_agent()->WaitForDisconnect();
47
210
  child->inspector_agent()->Stop();
48
210
}
49
#endif
50
51
}  // anonymous namespace
52
53
219
Worker::Worker(Environment* env,
54
               Local<Object> wrap,
55
               const std::string& url,
56
               std::shared_ptr<PerIsolateOptions> per_isolate_opts,
57
               std::vector<std::string>&& exec_argv)
58
    : AsyncWrap(env, wrap, AsyncWrap::PROVIDER_WORKER),
59
      per_isolate_opts_(per_isolate_opts),
60
      exec_argv_(exec_argv),
61
219
      platform_(env->isolate_data()->platform()),
62
      array_buffer_allocator_(ArrayBufferAllocator::Create()),
63
219
      start_profiler_idle_notifier_(env->profiler_idle_notifier_started()),
64
219
      thread_id_(Environment::AllocateThreadId()),
65
876
      env_vars_(env->env_vars()) {
66
219
  Debug(this, "Creating new worker instance with thread id %llu", thread_id_);
67
68
  // Set up everything that needs to be set up in the parent environment.
69
219
  parent_port_ = MessagePort::New(env, env->context());
70
219
  if (parent_port_ == nullptr) {
71
    // This can happen e.g. because execution is terminating.
72
219
    return;
73
  }
74
75
219
  child_port_data_ = std::make_unique<MessagePortData>(nullptr);
76
219
  MessagePort::Entangle(parent_port_, child_port_data_.get());
77
78
219
  object()->Set(env->context(),
79
                env->message_port_string(),
80
1314
                parent_port_->object()).Check();
81
82
219
  object()->Set(env->context(),
83
                env->thread_id_string(),
84
1314
                Number::New(env->isolate(), static_cast<double>(thread_id_)))
85
438
      .Check();
86
87
#if NODE_USE_V8_PLATFORM && HAVE_INSPECTOR
88
438
  inspector_parent_handle_ =
89
219
      env->inspector_agent()->GetParentHandle(thread_id_, url);
90
#endif
91
92
219
  argv_ = std::vector<std::string>{env->argv()[0]};
93
  // Mark this Worker object as weak until we actually start the thread.
94
219
  MakeWeak();
95
96
219
  Debug(this, "Preparation for worker %llu finished", thread_id_);
97
}
98
99
1865
bool Worker::is_stopped() const {
100
1865
  Mutex::ScopedLock lock(mutex_);
101
1865
  if (env_ != nullptr)
102
1241
    return env_->is_stopping();
103
624
  return stopped_;
104
}
105
106
3
std::shared_ptr<ArrayBufferAllocator> Worker::array_buffer_allocator() {
107
3
  return array_buffer_allocator_;
108
}
109
110
// This class contains data that is only relevant to the child thread itself,
111
// and only while it is running.
112
// (Eventually, the Environment instance should probably also be moved here.)
113
class WorkerThreadData {
114
 public:
115
218
  explicit WorkerThreadData(Worker* w)
116
218
    : w_(w) {
117
218
    CHECK_EQ(uv_loop_init(&loop_), 0);
118
119
218
    Isolate* isolate = NewIsolate(w->array_buffer_allocator_.get(), &loop_);
120
218
    CHECK_NOT_NULL(isolate);
121
122
    {
123
218
      Locker locker(isolate);
124
436
      Isolate::Scope isolate_scope(isolate);
125
218
      isolate->SetStackLimit(w_->stack_base_);
126
127
436
      HandleScope handle_scope(isolate);
128
      isolate_data_.reset(CreateIsolateData(isolate,
129
                                            &loop_,
130
                                            w_->platform_,
131
218
                                            w->array_buffer_allocator_.get()));
132
218
      CHECK(isolate_data_);
133
218
      if (w_->per_isolate_opts_)
134
227
        isolate_data_->set_options(std::move(w_->per_isolate_opts_));
135
    }
136
137
218
    Mutex::ScopedLock lock(w_->mutex_);
138
218
    w_->isolate_ = isolate;
139
218
  }
140
141
436
  ~WorkerThreadData() {
142
218
    Debug(w_, "Worker %llu dispose isolate", w_->thread_id_);
143
    Isolate* isolate;
144
    {
145
218
      Mutex::ScopedLock lock(w_->mutex_);
146
218
      isolate = w_->isolate_;
147
218
      w_->isolate_ = nullptr;
148
    }
149
150
218
    w_->platform_->CancelPendingDelayedTasks(isolate);
151
152
218
    bool platform_finished = false;
153
154
218
    isolate_data_.reset();
155
156
654
    w_->platform_->AddIsolateFinishedCallback(isolate, [](void* data) {
157
218
      *static_cast<bool*>(data) = true;
158
872
    }, &platform_finished);
159
218
    w_->platform_->UnregisterIsolate(isolate);
160
161
218
    isolate->Dispose();
162
163
    // Wait until the platform has cleaned up all relevant resources.
164
654
    while (!platform_finished)
165
218
      uv_run(&loop_, UV_RUN_ONCE);
166
167
218
    CheckedUvLoopClose(&loop_);
168
218
  }
169
170
 private:
171
  Worker* const w_;
172
  uv_loop_t loop_;
173
  DeleteFnPtr<IsolateData, FreeIsolateData> isolate_data_;
174
175
  friend class Worker;
176
};
177
178
218
void Worker::Run() {
179
218
  std::string name = "WorkerThread ";
180
218
  name += std::to_string(thread_id_);
181

438
  TRACE_EVENT_METADATA1(
182
      "__metadata", "thread_name", "name",
183
      TRACE_STR_COPY(name.c_str()));
184
218
  CHECK_NOT_NULL(platform_);
185
186
218
  Debug(this, "Creating isolate for worker with id %llu", thread_id_);
187
188
423
  WorkerThreadData data(this);
189
190
218
  Debug(this, "Starting worker with id %llu", thread_id_);
191
  {
192
218
    Locker locker(isolate_);
193
423
    Isolate::Scope isolate_scope(isolate_);
194
423
    SealHandleScope outer_seal(isolate_);
195
#if NODE_USE_V8_PLATFORM && HAVE_INSPECTOR
196
218
    bool inspector_started = false;
197
#endif
198
199
423
    DeleteFnPtr<Environment, FreeEnvironment> env_;
200
218
    OnScopeLeave cleanup_env([&]() {
201
436
      if (!env_) return;
202
210
      env_->set_can_call_into_js(false);
203
      Isolate::DisallowJavascriptExecutionScope disallow_js(isolate_,
204
210
          Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE);
205
206
      // Grab the parent-to-child channel and render is unusable.
207
      MessagePort* child_port;
208
      {
209
210
        Mutex::ScopedLock lock(mutex_);
210
210
        child_port = child_port_;
211
210
        child_port_ = nullptr;
212
      }
213
214
      {
215
210
        Context::Scope context_scope(env_->context());
216
210
        if (child_port != nullptr)
217
412
          child_port->Close();
218
        {
219
210
          Mutex::ScopedLock lock(mutex_);
220
210
          stopped_ = true;
221
210
          this->env_ = nullptr;
222
        }
223
210
        env_->thread_stopper()->set_stopped(true);
224
210
        env_->stop_sub_worker_contexts();
225
210
        env_->RunCleanup();
226
210
        RunAtExit(env_.get());
227
#if NODE_USE_V8_PLATFORM && HAVE_INSPECTOR
228
210
        if (inspector_started)
229
210
          WaitForWorkerInspectorToStop(env_.get());
230
#endif
231
232
        // This call needs to be made while the `Environment` is still alive
233
        // because we assume that it is available for async tracking in the
234
        // NodePlatform implementation.
235
210
        platform_->DrainTasks(isolate_);
236
      }
237
633
    });
238
239
218
    if (is_stopped()) return;
240
    {
241
212
      HandleScope handle_scope(isolate_);
242
212
      Local<Context> context = NewContext(isolate_);
243
244
212
      if (is_stopped()) return;
245
210
      CHECK(!context.IsEmpty());
246
205
      Context::Scope context_scope(context);
247
      {
248
        // TODO(addaleax): Use CreateEnvironment(), or generally another
249
        // public API.
250
        env_.reset(new Environment(data.isolate_data_.get(),
251
                                   context,
252
210
                                   std::move(argv_),
253
210
                                   std::move(exec_argv_),
254
                                   Environment::kNoFlags,
255
630
                                   thread_id_));
256
210
        CHECK_NOT_NULL(env_);
257
210
        env_->set_env_vars(std::move(env_vars_));
258
210
        env_->set_abort_on_uncaught_exception(false);
259
210
        env_->set_worker_context(this);
260
261
210
        env_->InitializeLibuv(start_profiler_idle_notifier_);
262
      }
263
      {
264
210
        Mutex::ScopedLock lock(mutex_);
265
210
        if (stopped_) return;
266
210
        this->env_ = env_.get();
267
      }
268
210
      Debug(this, "Created Environment for worker with id %llu", thread_id_);
269
210
      if (is_stopped()) return;
270
      {
271
210
        env_->InitializeDiagnostics();
272
#if NODE_USE_V8_PLATFORM && HAVE_INSPECTOR
273
210
        env_->InitializeInspector(inspector_parent_handle_.release());
274
210
        inspector_started = true;
275
#endif
276
210
        HandleScope handle_scope(isolate_);
277
420
        AsyncCallbackScope callback_scope(env_.get());
278
210
        env_->async_hooks()->push_async_ids(1, 0);
279
420
        if (!env_->RunBootstrapping().IsEmpty()) {
280
206
          CreateEnvMessagePort(env_.get());
281
206
          if (is_stopped()) return;
282
206
          Debug(this, "Created message port for worker %llu", thread_id_);
283
206
          USE(StartExecution(env_.get(), "internal/main/worker_thread"));
284
        }
285
286
210
        env_->async_hooks()->pop_async_id(1);
287
288
420
        Debug(this, "Loaded environment for worker %llu", thread_id_);
289
      }
290
291
210
      if (is_stopped()) return;
292
      {
293
205
        SealHandleScope seal(isolate_);
294
        bool more;
295
        env_->performance_state()->Mark(
296
205
            node::performance::NODE_PERFORMANCE_MILESTONE_LOOP_START);
297
149
        do {
298
205
          if (is_stopped()) break;
299
205
          uv_run(&data.loop_, UV_RUN_DEFAULT);
300
205
          if (is_stopped()) break;
301
302
149
          platform_->DrainTasks(isolate_);
303
304
149
          more = uv_loop_alive(&data.loop_);
305

149
          if (more && !is_stopped()) continue;
306
307
149
          EmitBeforeExit(env_.get());
308
309
          // Emit `beforeExit` if the loop became alive either after emitting
310
          // event, or after running some callbacks.
311
149
          more = uv_loop_alive(&data.loop_);
312

149
        } while (more == true && !is_stopped());
313
        env_->performance_state()->Mark(
314
205
            node::performance::NODE_PERFORMANCE_MILESTONE_LOOP_EXIT);
315
205
      }
316
    }
317
318
    {
319
      int exit_code;
320
205
      bool stopped = is_stopped();
321
205
      if (!stopped)
322
149
        exit_code = EmitExit(env_.get());
323
205
      Mutex::ScopedLock lock(mutex_);
324

205
      if (exit_code_ == 0 && !stopped)
325
146
        exit_code_ = exit_code;
326
327
#if HAVE_INSPECTOR
328
205
      profiler::EndStartedProfilers(env_.get());
329
#endif
330
      Debug(this, "Exiting thread for worker %llu with exit code %d",
331
410
            thread_id_, exit_code_);
332
205
    }
333
  }
334
335
410
  Debug(this, "Worker %llu thread stops", thread_id_);
336
}
337
338
206
void Worker::CreateEnvMessagePort(Environment* env) {
339
206
  HandleScope handle_scope(isolate_);
340
412
  Mutex::ScopedLock lock(mutex_);
341
  // Set up the message channel for receiving messages in the child.
342
  child_port_ = MessagePort::New(env,
343
                                 env->context(),
344
206
                                 std::move(child_port_data_));
345
  // MessagePort::New() may return nullptr if execution is terminated
346
  // within it.
347
206
  if (child_port_ != nullptr)
348
412
    env->set_message_port(child_port_->object(isolate_));
349
206
}
350
351
218
void Worker::JoinThread() {
352
218
  if (thread_joined_)
353
213
    return;
354
218
  CHECK_EQ(uv_thread_join(&tid_), 0);
355
218
  thread_joined_ = true;
356
357
218
  env()->remove_sub_worker_context(this);
358
218
  on_thread_finished_.Uninstall();
359
360
  {
361
218
    HandleScope handle_scope(env()->isolate());
362
218
    Context::Scope context_scope(env()->context());
363
364
    // Reset the parent port as we're closing it now anyway.
365
218
    object()->Set(env()->context(),
366
                  env()->message_port_string(),
367
1308
                  Undefined(env()->isolate())).Check();
368
369
218
    Local<Value> code = Integer::New(env()->isolate(), exit_code_);
370
431
    MakeCallback(env()->onexit_string(), 1, &code);
371
  }
372
373
  // We cleared all libuv handles bound to this Worker above,
374
  // the C++ object is no longer needed for anything now.
375
213
  MakeWeak();
376
}
377
378
579
Worker::~Worker() {
379
193
  Mutex::ScopedLock lock(mutex_);
380
381
193
  CHECK(stopped_);
382
193
  CHECK_NULL(env_);
383
193
  CHECK(thread_joined_);
384
385
386
  Debug(this, "Worker %llu destroyed", thread_id_);
386
386
}
387
388
222
void Worker::New(const FunctionCallbackInfo<Value>& args) {
389
222
  Environment* env = Environment::GetCurrent(args);
390
391
222
  CHECK(args.IsConstructCall());
392
393
222
  if (env->isolate_data()->platform() == nullptr) {
394
    THROW_ERR_MISSING_PLATFORM_FOR_WORKER(env);
395
    return;
396
  }
397
398
222
  std::string url;
399
441
  std::shared_ptr<PerIsolateOptions> per_isolate_opts = nullptr;
400
401
441
  std::vector<std::string> exec_argv_out;
402
222
  bool has_explicit_exec_argv = false;
403
404
222
  CHECK_EQ(args.Length(), 2);
405
  // Argument might be a string or URL
406
666
  if (!args[0]->IsNullOrUndefined()) {
407
    Utf8Value value(
408
        args.GetIsolate(),
409
364
        args[0]->ToString(env->context()).FromMaybe(Local<String>()));
410
91
    url.append(value.out(), value.length());
411
  }
412
413
444
  if (args[1]->IsArray()) {
414
24
    Local<Array> array = args[1].As<Array>();
415
    // The first argument is reserved for program name, but we don't need it
416
    // in workers.
417
12
    has_explicit_exec_argv = true;
418
12
    std::vector<std::string> exec_argv = {""};
419
12
    uint32_t length = array->Length();
420
58
    for (uint32_t i = 0; i < length; i++) {
421
      Local<Value> arg;
422
51
      if (!array->Get(env->context(), i).ToLocal(&arg)) {
423
        return;
424
      }
425
      MaybeLocal<String> arg_v8_string =
426
34
          arg->ToString(env->context());
427
17
      if (arg_v8_string.IsEmpty()) {
428
        return;
429
      }
430
      Utf8Value arg_utf8_value(
431
          args.GetIsolate(),
432
17
          arg_v8_string.FromMaybe(Local<String>()));
433
34
      std::string arg_string(arg_utf8_value.out(), arg_utf8_value.length());
434
17
      exec_argv.push_back(arg_string);
435
17
    }
436
437
21
    std::vector<std::string> invalid_args{};
438
21
    std::vector<std::string> errors{};
439
12
    per_isolate_opts.reset(new PerIsolateOptions());
440
441
    // Using invalid_args as the v8_args argument as it stores unknown
442
    // options for the per isolate parser.
443
    options_parser::Parse(
444
        &exec_argv,
445
        &exec_argv_out,
446
        &invalid_args,
447
        per_isolate_opts.get(),
448
        kDisallowedInEnvironment,
449
12
        &errors);
450
451
    // The first argument is program name.
452
12
    invalid_args.erase(invalid_args.begin());
453

12
    if (errors.size() > 0 || invalid_args.size() > 0) {
454
      Local<Value> error;
455
6
      if (!ToV8Value(env->context(),
456
3
                     errors.size() > 0 ? errors : invalid_args)
457
9
                         .ToLocal(&error)) {
458
        return;
459
      }
460
      Local<String> key =
461
3
          FIXED_ONE_BYTE_STRING(env->isolate(), "invalidExecArgv");
462
      // Ignore the return value of Set() because exceptions bubble up to JS
463
      // when we return anyway.
464
9
      USE(args.This()->Set(env->context(), key, error));
465
3
      return;
466
9
    }
467
  }
468
219
  if (!has_explicit_exec_argv)
469
210
    exec_argv_out = env->exec_argv();
470
438
  new Worker(env, args.This(), url, per_isolate_opts, std::move(exec_argv_out));
471
}
472
473
217
void Worker::CloneParentEnvVars(const FunctionCallbackInfo<Value>& args) {
474
  Worker* w;
475
434
  ASSIGN_OR_RETURN_UNWRAP(&w, args.This());
476
217
  CHECK(w->thread_joined_);  // The Worker has not started yet.
477
478
434
  w->env_vars_ = w->env()->env_vars()->Clone(args.GetIsolate());
479
}
480
481
1
void Worker::SetEnvVars(const FunctionCallbackInfo<Value>& args) {
482
  Worker* w;
483
2
  ASSIGN_OR_RETURN_UNWRAP(&w, args.This());
484
1
  CHECK(w->thread_joined_);  // The Worker has not started yet.
485
486
2
  CHECK(args[0]->IsObject());
487
1
  w->env_vars_ = KVStore::CreateMapKVStore();
488
1
  w->env_vars_->AssignFromObject(args.GetIsolate()->GetCurrentContext(),
489
3
                                args[0].As<Object>());
490
}
491
492
218
void Worker::StartThread(const FunctionCallbackInfo<Value>& args) {
493
  Worker* w;
494
436
  ASSIGN_OR_RETURN_UNWRAP(&w, args.This());
495
218
  Mutex::ScopedLock lock(w->mutex_);
496
497
  // The object now owns the created thread and should not be garbage collected
498
  // until that finishes.
499
218
  w->ClearWeak();
500
501
218
  w->env()->add_sub_worker_context(w);
502
218
  w->stopped_ = false;
503
218
  w->thread_joined_ = false;
504
505
606
  w->on_thread_finished_.Install(w->env(), w, [](uv_async_t* handle) {
506
194
    Worker* w_ = static_cast<Worker*>(handle->data);
507
194
    CHECK(w_->is_stopped());
508
194
    w_->parent_port_ = nullptr;
509
194
    w_->JoinThread();
510
190
    delete w_;
511
820
  });
512
513
  uv_thread_options_t thread_options;
514
218
  thread_options.flags = UV_THREAD_HAS_STACK_SIZE;
515
218
  thread_options.stack_size = kStackSize;
516
872
  CHECK_EQ(uv_thread_create_ex(&w->tid_, &thread_options, [](void* arg) {
517
    Worker* w = static_cast<Worker*>(arg);
518
    const uintptr_t stack_top = reinterpret_cast<uintptr_t>(&arg);
519
520
    // Leave a few kilobytes just to make sure we're within limits and have
521
    // some space to do work in C++ land.
522
    w->stack_base_ = stack_top - (kStackSize - kStackBufferSize);
523
524
    w->Run();
525
526
    Mutex::ScopedLock lock(w->mutex_);
527
    w->on_thread_finished_.Stop();
528
218
  }, static_cast<void*>(w)), 0);
529
}
530
531
29
void Worker::StopThread(const FunctionCallbackInfo<Value>& args) {
532
  Worker* w;
533
58
  ASSIGN_OR_RETURN_UNWRAP(&w, args.This());
534
535
29
  Debug(w, "Worker %llu is getting stopped by parent", w->thread_id_);
536
29
  w->Exit(1);
537
}
538
539
31
void Worker::Ref(const FunctionCallbackInfo<Value>& args) {
540
  Worker* w;
541
62
  ASSIGN_OR_RETURN_UNWRAP(&w, args.This());
542
31
  uv_ref(reinterpret_cast<uv_handle_t*>(w->on_thread_finished_.GetHandle()));
543
}
544
545
5
void Worker::Unref(const FunctionCallbackInfo<Value>& args) {
546
  Worker* w;
547
10
  ASSIGN_OR_RETURN_UNWRAP(&w, args.This());
548
5
  uv_unref(reinterpret_cast<uv_handle_t*>(w->on_thread_finished_.GetHandle()));
549
}
550
551
80
void Worker::Exit(int code) {
552
80
  Mutex::ScopedLock lock(mutex_);
553
80
  Debug(this, "Worker %llu called Exit(%d)", thread_id_, code);
554
80
  if (env_ != nullptr) {
555
66
    exit_code_ = code;
556
66
    Stop(env_);
557
  } else {
558
14
    stopped_ = true;
559
80
  }
560
80
}
561
562
namespace {
563
564
// Return the MessagePort that is global for this Environment and communicates
565
// with the internal [kPort] port of the JS Worker class in the parent thread.
566
410
void GetEnvMessagePort(const FunctionCallbackInfo<Value>& args) {
567
410
  Environment* env = Environment::GetCurrent(args);
568
411
  Local<Object> port = env->message_port();
569
411
  if (!port.IsEmpty()) {
570
1233
    CHECK_EQ(port->CreationContext()->GetIsolate(), args.GetIsolate());
571
822
    args.GetReturnValue().Set(port);
572
  }
573
411
}
574
575
3616
void InitWorker(Local<Object> target,
576
                Local<Value> unused,
577
                Local<Context> context,
578
                void* priv) {
579
3616
  Environment* env = Environment::GetCurrent(context);
580
581
  {
582
3616
    Local<FunctionTemplate> w = env->NewFunctionTemplate(Worker::New);
583
584
7232
    w->InstanceTemplate()->SetInternalFieldCount(1);
585
7232
    w->Inherit(AsyncWrap::GetConstructorTemplate(env));
586
587
3616
    env->SetProtoMethod(w, "setEnvVars", Worker::SetEnvVars);
588
3616
    env->SetProtoMethod(w, "cloneParentEnvVars", Worker::CloneParentEnvVars);
589
3616
    env->SetProtoMethod(w, "startThread", Worker::StartThread);
590
3616
    env->SetProtoMethod(w, "stopThread", Worker::StopThread);
591
3616
    env->SetProtoMethod(w, "ref", Worker::Ref);
592
3616
    env->SetProtoMethod(w, "unref", Worker::Unref);
593
594
    Local<String> workerString =
595
3616
        FIXED_ONE_BYTE_STRING(env->isolate(), "Worker");
596
3616
    w->SetClassName(workerString);
597
    target->Set(env->context(),
598
                workerString,
599
18080
                w->GetFunction(env->context()).ToLocalChecked()).Check();
600
  }
601
602
3616
  env->SetMethod(target, "getEnvMessagePort", GetEnvMessagePort);
603
604
  target
605
      ->Set(env->context(),
606
            env->thread_id_string(),
607
18080
            Number::New(env->isolate(), static_cast<double>(env->thread_id())))
608
7232
      .Check();
609
610
  target
611
      ->Set(env->context(),
612
            FIXED_ONE_BYTE_STRING(env->isolate(), "isMainThread"),
613
18080
            Boolean::New(env->isolate(), env->is_main_thread()))
614
7232
      .Check();
615
616
  target
617
      ->Set(env->context(),
618
            FIXED_ONE_BYTE_STRING(env->isolate(), "ownsProcessState"),
619
18080
            Boolean::New(env->isolate(), env->owns_process_state()))
620
7232
      .Check();
621
3616
}
622
623
}  // anonymous namespace
624
625
}  // namespace worker
626
}  // namespace node
627
628
4981
NODE_MODULE_CONTEXT_AWARE_INTERNAL(worker, node::worker::InitWorker)