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-09-23 22:30:09 Branches: 120 172 69.8 %

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
206
void WaitForWorkerInspectorToStop(Environment* child) {
46
206
  child->inspector_agent()->WaitForDisconnect();
47
206
  child->inspector_agent()->Stop();
48
206
}
49
#endif
50
51
}  // anonymous namespace
52
53
217
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
217
      platform_(env->isolate_data()->platform()),
62
      array_buffer_allocator_(ArrayBufferAllocator::Create()),
63
217
      start_profiler_idle_notifier_(env->profiler_idle_notifier_started()),
64
217
      thread_id_(Environment::AllocateThreadId()),
65
868
      env_vars_(env->env_vars()) {
66
217
  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
217
  parent_port_ = MessagePort::New(env, env->context());
70
217
  if (parent_port_ == nullptr) {
71
    // This can happen e.g. because execution is terminating.
72
217
    return;
73
  }
74
75
217
  child_port_data_ = std::make_unique<MessagePortData>(nullptr);
76
217
  MessagePort::Entangle(parent_port_, child_port_data_.get());
77
78
217
  object()->Set(env->context(),
79
                env->message_port_string(),
80
1302
                parent_port_->object()).Check();
81
82
217
  object()->Set(env->context(),
83
                env->thread_id_string(),
84
1302
                Number::New(env->isolate(), static_cast<double>(thread_id_)))
85
434
      .Check();
86
87
#if NODE_USE_V8_PLATFORM && HAVE_INSPECTOR
88
434
  inspector_parent_handle_ =
89
217
      env->inspector_agent()->GetParentHandle(thread_id_, url);
90
#endif
91
92
217
  argv_ = std::vector<std::string>{env->argv()[0]};
93
  // Mark this Worker object as weak until we actually start the thread.
94
217
  MakeWeak();
95
96
217
  Debug(this, "Preparation for worker %llu finished", thread_id_);
97
}
98
99
1853
bool Worker::is_stopped() const {
100
1853
  Mutex::ScopedLock lock(mutex_);
101
1853
  if (env_ != nullptr)
102
1236
    return env_->is_stopping();
103
617
  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
216
  explicit WorkerThreadData(Worker* w)
116
216
    : w_(w) {
117
216
    CHECK_EQ(uv_loop_init(&loop_), 0);
118
119
216
    Isolate* isolate = NewIsolate(w->array_buffer_allocator_.get(), &loop_);
120
216
    CHECK_NOT_NULL(isolate);
121
122
    {
123
216
      Locker locker(isolate);
124
432
      Isolate::Scope isolate_scope(isolate);
125
216
      isolate->SetStackLimit(w_->stack_base_);
126
127
432
      HandleScope handle_scope(isolate);
128
      isolate_data_.reset(CreateIsolateData(isolate,
129
                                            &loop_,
130
                                            w_->platform_,
131
216
                                            w->array_buffer_allocator_.get()));
132
216
      CHECK(isolate_data_);
133
216
      if (w_->per_isolate_opts_)
134
225
        isolate_data_->set_options(std::move(w_->per_isolate_opts_));
135
    }
136
137
216
    Mutex::ScopedLock lock(w_->mutex_);
138
216
    w_->isolate_ = isolate;
139
216
  }
140
141
432
  ~WorkerThreadData() {
142
216
    Debug(w_, "Worker %llu dispose isolate", w_->thread_id_);
143
    Isolate* isolate;
144
    {
145
216
      Mutex::ScopedLock lock(w_->mutex_);
146
216
      isolate = w_->isolate_;
147
216
      w_->isolate_ = nullptr;
148
    }
149
150
216
    w_->platform_->CancelPendingDelayedTasks(isolate);
151
152
216
    bool platform_finished = false;
153
154
216
    isolate_data_.reset();
155
156
647
    w_->platform_->AddIsolateFinishedCallback(isolate, [](void* data) {
157
216
      *static_cast<bool*>(data) = true;
158
863
    }, &platform_finished);
159
216
    w_->platform_->UnregisterIsolate(isolate);
160
161
216
    isolate->Dispose();
162
163
    // Wait until the platform has cleaned up all relevant resources.
164
648
    while (!platform_finished)
165
216
      uv_run(&loop_, UV_RUN_ONCE);
166
167
216
    CheckedUvLoopClose(&loop_);
168
216
  }
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
216
void Worker::Run() {
179
216
  std::string name = "WorkerThread ";
180
216
  name += std::to_string(thread_id_);
181

434
  TRACE_EVENT_METADATA1(
182
      "__metadata", "thread_name", "name",
183
      TRACE_STR_COPY(name.c_str()));
184
216
  CHECK_NOT_NULL(platform_);
185
186
216
  Debug(this, "Creating isolate for worker with id %llu", thread_id_);
187
188
422
  WorkerThreadData data(this);
189
190
216
  Debug(this, "Starting worker with id %llu", thread_id_);
191
  {
192
216
    Locker locker(isolate_);
193
422
    Isolate::Scope isolate_scope(isolate_);
194
422
    SealHandleScope outer_seal(isolate_);
195
#if NODE_USE_V8_PLATFORM && HAVE_INSPECTOR
196
216
    bool inspector_started = false;
197
#endif
198
199
422
    DeleteFnPtr<Environment, FreeEnvironment> env_;
200
216
    OnScopeLeave cleanup_env([&]() {
201
432
      if (!env_) return;
202
206
      env_->set_can_call_into_js(false);
203
      Isolate::DisallowJavascriptExecutionScope disallow_js(isolate_,
204
206
          Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE);
205
206
      // Grab the parent-to-child channel and render is unusable.
207
      MessagePort* child_port;
208
      {
209
206
        Mutex::ScopedLock lock(mutex_);
210
206
        child_port = child_port_;
211
206
        child_port_ = nullptr;
212
      }
213
214
      {
215
206
        Context::Scope context_scope(env_->context());
216
206
        if (child_port != nullptr)
217
412
          child_port->Close();
218
        {
219
206
          Mutex::ScopedLock lock(mutex_);
220
206
          stopped_ = true;
221
206
          this->env_ = nullptr;
222
        }
223
206
        env_->thread_stopper()->set_stopped(true);
224
206
        env_->stop_sub_worker_contexts();
225
206
        env_->RunCleanup();
226
206
        RunAtExit(env_.get());
227
#if NODE_USE_V8_PLATFORM && HAVE_INSPECTOR
228
206
        if (inspector_started)
229
206
          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
206
        platform_->DrainTasks(isolate_);
236
      }
237
628
    });
238
239
216
    if (is_stopped()) return;
240
    {
241
208
      HandleScope handle_scope(isolate_);
242
208
      Local<Context> context = NewContext(isolate_);
243
244
208
      if (is_stopped()) return;
245
206
      CHECK(!context.IsEmpty());
246
206
      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
206
                                   std::move(argv_),
253
206
                                   std::move(exec_argv_),
254
                                   Environment::kNoFlags,
255
618
                                   thread_id_));
256
206
        CHECK_NOT_NULL(env_);
257
206
        env_->set_env_vars(std::move(env_vars_));
258
206
        env_->set_abort_on_uncaught_exception(false);
259
206
        env_->set_worker_context(this);
260
261
206
        env_->InitializeLibuv(start_profiler_idle_notifier_);
262
      }
263
      {
264
206
        Mutex::ScopedLock lock(mutex_);
265
206
        if (stopped_) return;
266
206
        this->env_ = env_.get();
267
      }
268
206
      Debug(this, "Created Environment for worker with id %llu", thread_id_);
269
206
      if (is_stopped()) return;
270
      {
271
206
        env_->InitializeDiagnostics();
272
#if NODE_USE_V8_PLATFORM && HAVE_INSPECTOR
273
206
        env_->InitializeInspector(inspector_parent_handle_.release());
274
206
        inspector_started = true;
275
#endif
276
206
        HandleScope handle_scope(isolate_);
277
412
        AsyncCallbackScope callback_scope(env_.get());
278
206
        env_->async_hooks()->push_async_ids(1, 0);
279
412
        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
206
        env_->async_hooks()->pop_async_id(1);
287
288
412
        Debug(this, "Loaded environment for worker %llu", thread_id_);
289
      }
290
291
206
      if (is_stopped()) return;
292
      {
293
206
        SealHandleScope seal(isolate_);
294
        bool more;
295
        env_->performance_state()->Mark(
296
206
            node::performance::NODE_PERFORMANCE_MILESTONE_LOOP_START);
297
150
        do {
298
206
          if (is_stopped()) break;
299
206
          uv_run(&data.loop_, UV_RUN_DEFAULT);
300
206
          if (is_stopped()) break;
301
302
150
          platform_->DrainTasks(isolate_);
303
304
150
          more = uv_loop_alive(&data.loop_);
305

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

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

206
      if (exit_code_ == 0 && !stopped)
325
147
        exit_code_ = exit_code;
326
327
#if HAVE_INSPECTOR
328
206
      profiler::EndStartedProfilers(env_.get());
329
#endif
330
      Debug(this, "Exiting thread for worker %llu with exit code %d",
331
412
            thread_id_, exit_code_);
332
206
    }
333
  }
334
335
412
  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
216
void Worker::JoinThread() {
352
216
  if (thread_joined_)
353
212
    return;
354
216
  CHECK_EQ(uv_thread_join(&tid_), 0);
355
216
  thread_joined_ = true;
356
357
216
  env()->remove_sub_worker_context(this);
358
216
  on_thread_finished_.Uninstall();
359
360
  {
361
216
    HandleScope handle_scope(env()->isolate());
362
216
    Context::Scope context_scope(env()->context());
363
364
    // Reset the parent port as we're closing it now anyway.
365
216
    object()->Set(env()->context(),
366
                  env()->message_port_string(),
367
1296
                  Undefined(env()->isolate())).Check();
368
369
216
    Local<Value> code = Integer::New(env()->isolate(), exit_code_);
370
428
    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
212
  MakeWeak();
376
}
377
378
576
Worker::~Worker() {
379
192
  Mutex::ScopedLock lock(mutex_);
380
381
192
  CHECK(stopped_);
382
192
  CHECK_NULL(env_);
383
192
  CHECK(thread_joined_);
384
385
384
  Debug(this, "Worker %llu destroyed", thread_id_);
386
384
}
387
388
220
void Worker::New(const FunctionCallbackInfo<Value>& args) {
389
220
  Environment* env = Environment::GetCurrent(args);
390
391
220
  CHECK(args.IsConstructCall());
392
393
220
  if (env->isolate_data()->platform() == nullptr) {
394
    THROW_ERR_MISSING_PLATFORM_FOR_WORKER(env);
395
    return;
396
  }
397
398
220
  std::string url;
399
437
  std::shared_ptr<PerIsolateOptions> per_isolate_opts = nullptr;
400
401
437
  std::vector<std::string> exec_argv_out;
402
220
  bool has_explicit_exec_argv = false;
403
404
220
  CHECK_EQ(args.Length(), 2);
405
  // Argument might be a string or URL
406
660
  if (!args[0]->IsNullOrUndefined()) {
407
    Utf8Value value(
408
        args.GetIsolate(),
409
356
        args[0]->ToString(env->context()).FromMaybe(Local<String>()));
410
89
    url.append(value.out(), value.length());
411
  }
412
413
440
  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
217
  if (!has_explicit_exec_argv)
469
208
    exec_argv_out = env->exec_argv();
470
434
  new Worker(env, args.This(), url, per_isolate_opts, std::move(exec_argv_out));
471
}
472
473
215
void Worker::CloneParentEnvVars(const FunctionCallbackInfo<Value>& args) {
474
  Worker* w;
475
430
  ASSIGN_OR_RETURN_UNWRAP(&w, args.This());
476
215
  CHECK(w->thread_joined_);  // The Worker has not started yet.
477
478
430
  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
216
void Worker::StartThread(const FunctionCallbackInfo<Value>& args) {
493
  Worker* w;
494
432
  ASSIGN_OR_RETURN_UNWRAP(&w, args.This());
495
216
  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
216
  w->ClearWeak();
500
501
216
  w->env()->add_sub_worker_context(w);
502
216
  w->stopped_ = false;
503
216
  w->thread_joined_ = false;
504
505
602
  w->on_thread_finished_.Install(w->env(), w, [](uv_async_t* handle) {
506
193
    Worker* w_ = static_cast<Worker*>(handle->data);
507
193
    CHECK(w_->is_stopped());
508
193
    w_->parent_port_ = nullptr;
509
193
    w_->JoinThread();
510
189
    delete w_;
511
814
  });
512
513
  uv_thread_options_t thread_options;
514
216
  thread_options.flags = UV_THREAD_HAS_STACK_SIZE;
515
216
  thread_options.stack_size = kStackSize;
516
864
  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
216
  }, 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
78
void Worker::Exit(int code) {
552
78
  Mutex::ScopedLock lock(mutex_);
553
78
  Debug(this, "Worker %llu called Exit(%d)", thread_id_, code);
554
78
  if (env_ != nullptr) {
555
61
    exit_code_ = code;
556
61
    Stop(env_);
557
  } else {
558
17
    stopped_ = true;
559
78
  }
560
78
}
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
413
void GetEnvMessagePort(const FunctionCallbackInfo<Value>& args) {
567
413
  Environment* env = Environment::GetCurrent(args);
568
413
  Local<Object> port = env->message_port();
569
413
  if (!port.IsEmpty()) {
570
1239
    CHECK_EQ(port->CreationContext()->GetIsolate(), args.GetIsolate());
571
826
    args.GetReturnValue().Set(port);
572
  }
573
413
}
574
575
3598
void InitWorker(Local<Object> target,
576
                Local<Value> unused,
577
                Local<Context> context,
578
                void* priv) {
579
3598
  Environment* env = Environment::GetCurrent(context);
580
581
  {
582
3598
    Local<FunctionTemplate> w = env->NewFunctionTemplate(Worker::New);
583
584
7196
    w->InstanceTemplate()->SetInternalFieldCount(1);
585
7196
    w->Inherit(AsyncWrap::GetConstructorTemplate(env));
586
587
3598
    env->SetProtoMethod(w, "setEnvVars", Worker::SetEnvVars);
588
3598
    env->SetProtoMethod(w, "cloneParentEnvVars", Worker::CloneParentEnvVars);
589
3598
    env->SetProtoMethod(w, "startThread", Worker::StartThread);
590
3598
    env->SetProtoMethod(w, "stopThread", Worker::StopThread);
591
3598
    env->SetProtoMethod(w, "ref", Worker::Ref);
592
3598
    env->SetProtoMethod(w, "unref", Worker::Unref);
593
594
    Local<String> workerString =
595
3598
        FIXED_ONE_BYTE_STRING(env->isolate(), "Worker");
596
3598
    w->SetClassName(workerString);
597
    target->Set(env->context(),
598
                workerString,
599
17990
                w->GetFunction(env->context()).ToLocalChecked()).Check();
600
  }
601
602
3598
  env->SetMethod(target, "getEnvMessagePort", GetEnvMessagePort);
603
604
  target
605
      ->Set(env->context(),
606
            env->thread_id_string(),
607
17990
            Number::New(env->isolate(), static_cast<double>(env->thread_id())))
608
7196
      .Check();
609
610
  target
611
      ->Set(env->context(),
612
            FIXED_ONE_BYTE_STRING(env->isolate(), "isMainThread"),
613
17990
            Boolean::New(env->isolate(), env->is_main_thread()))
614
7196
      .Check();
615
616
  target
617
      ->Set(env->context(),
618
            FIXED_ONE_BYTE_STRING(env->isolate(), "ownsProcessState"),
619
17990
            Boolean::New(env->isolate(), env->owns_process_state()))
620
7196
      .Check();
621
3598
}
622
623
}  // anonymous namespace
624
625
}  // namespace worker
626
}  // namespace node
627
628
5047
NODE_MODULE_CONTEXT_AWARE_INTERNAL(worker, node::worker::InitWorker)