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: 301 306 98.4 %
Date: 2019-08-17 22:35:23 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
201
void WaitForWorkerInspectorToStop(Environment* child) {
46
201
  child->inspector_agent()->WaitForDisconnect();
47
201
  child->inspector_agent()->Stop();
48
201
}
49
#endif
50
51
}  // anonymous namespace
52
53
211
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
211
      platform_(env->isolate_data()->platform()),
62
211
      start_profiler_idle_notifier_(env->profiler_idle_notifier_started()),
63
211
      thread_id_(Environment::AllocateThreadId()),
64
844
      env_vars_(env->env_vars()) {
65
211
  Debug(this, "Creating new worker instance with thread id %llu", thread_id_);
66
67
  // Set up everything that needs to be set up in the parent environment.
68
211
  parent_port_ = MessagePort::New(env, env->context());
69
211
  if (parent_port_ == nullptr) {
70
    // This can happen e.g. because execution is terminating.
71
211
    return;
72
  }
73
74
211
  child_port_data_ = std::make_unique<MessagePortData>(nullptr);
75
211
  MessagePort::Entangle(parent_port_, child_port_data_.get());
76
77
211
  object()->Set(env->context(),
78
                env->message_port_string(),
79
1266
                parent_port_->object()).Check();
80
81
211
  object()->Set(env->context(),
82
                env->thread_id_string(),
83
1266
                Number::New(env->isolate(), static_cast<double>(thread_id_)))
84
422
      .Check();
85
86
#if NODE_USE_V8_PLATFORM && HAVE_INSPECTOR
87
422
  inspector_parent_handle_ =
88
211
      env->inspector_agent()->GetParentHandle(thread_id_, url);
89
#endif
90
91
211
  argv_ = std::vector<std::string>{env->argv()[0]};
92
  // Mark this Worker object as weak until we actually start the thread.
93
211
  MakeWeak();
94
95
211
  Debug(this, "Preparation for worker %llu finished", thread_id_);
96
}
97
98
1781
bool Worker::is_stopped() const {
99
1781
  Mutex::ScopedLock lock(mutex_);
100
1782
  if (env_ != nullptr)
101
1184
    return env_->is_stopping();
102
598
  return stopped_;
103
}
104
105
// This class contains data that is only relevant to the child thread itself,
106
// and only while it is running.
107
// (Eventually, the Environment instance should probably also be moved here.)
108
class WorkerThreadData {
109
 public:
110
210
  explicit WorkerThreadData(Worker* w)
111
    : w_(w),
112
210
      array_buffer_allocator_(ArrayBufferAllocator::Create()) {
113
210
    CHECK_EQ(uv_loop_init(&loop_), 0);
114
115
210
    Isolate* isolate = NewIsolate(array_buffer_allocator_.get(), &loop_);
116
210
    CHECK_NOT_NULL(isolate);
117
118
    {
119
210
      Locker locker(isolate);
120
420
      Isolate::Scope isolate_scope(isolate);
121
210
      isolate->SetStackLimit(w_->stack_base_);
122
123
420
      HandleScope handle_scope(isolate);
124
      isolate_data_.reset(CreateIsolateData(isolate,
125
                                            &loop_,
126
                                            w_->platform_,
127
210
                                            array_buffer_allocator_.get()));
128
210
      CHECK(isolate_data_);
129
210
      if (w_->per_isolate_opts_)
130
219
        isolate_data_->set_options(std::move(w_->per_isolate_opts_));
131
    }
132
133
210
    Mutex::ScopedLock lock(w_->mutex_);
134
210
    w_->isolate_ = isolate;
135
210
  }
136
137
419
  ~WorkerThreadData() {
138
209
    Debug(w_, "Worker %llu dispose isolate", w_->thread_id_);
139
    Isolate* isolate;
140
    {
141
210
      Mutex::ScopedLock lock(w_->mutex_);
142
210
      isolate = w_->isolate_;
143
210
      w_->isolate_ = nullptr;
144
    }
145
146
210
    w_->platform_->CancelPendingDelayedTasks(isolate);
147
148
210
    bool platform_finished = false;
149
150
210
    isolate_data_.reset();
151
152
630
    w_->platform_->AddIsolateFinishedCallback(isolate, [](void* data) {
153
210
      *static_cast<bool*>(data) = true;
154
840
    }, &platform_finished);
155
210
    w_->platform_->UnregisterIsolate(isolate);
156
157
210
    isolate->Dispose();
158
159
    // Wait until the platform has cleaned up all relevant resources.
160
630
    while (!platform_finished)
161
210
      uv_run(&loop_, UV_RUN_ONCE);
162
163
210
    CheckedUvLoopClose(&loop_);
164
210
  }
165
166
 private:
167
  Worker* const w_;
168
  uv_loop_t loop_;
169
  std::unique_ptr<ArrayBufferAllocator> array_buffer_allocator_;
170
  DeleteFnPtr<IsolateData, FreeIsolateData> isolate_data_;
171
172
  friend class Worker;
173
};
174
175
210
void Worker::Run() {
176
210
  std::string name = "WorkerThread ";
177
210
  name += std::to_string(thread_id_);
178

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

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

141
        } while (more == true && !is_stopped());
310
        env_->performance_state()->Mark(
311
194
            node::performance::NODE_PERFORMANCE_MILESTONE_LOOP_EXIT);
312
195
      }
313
    }
314
315
    {
316
      int exit_code;
317
195
      bool stopped = is_stopped();
318
194
      if (!stopped)
319
142
        exit_code = EmitExit(env_.get());
320
193
      Mutex::ScopedLock lock(mutex_);
321

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

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