GCC Code Coverage Report
Directory: ../ Exec Total Coverage
File: /home/iojs/build/workspace/node-test-commit-linux-coverage/nodes/benchmark/out/../src/inspector_agent.cc Lines: 287 334 85.9 %
Date: 2017-11-19 Branches: 74 118 62.7 %

Line Branch Exec Source
1
#include "inspector_agent.h"
2
3
#include "inspector_io.h"
4
#include "node_internals.h"
5
#include "v8-inspector.h"
6
#include "v8-platform.h"
7
8
#include "libplatform/libplatform.h"
9
10
#include <string.h>
11
#include <sstream>
12
#include <unordered_map>
13
#include <vector>
14
15
#ifdef __POSIX__
16
#include <limits.h>
17
#include <unistd.h>  // setuid, getuid
18
#endif  // __POSIX__
19
20
namespace node {
21
namespace inspector {
22
namespace {
23
24
using node::FatalError;
25
26
using v8::Array;
27
using v8::Context;
28
using v8::Function;
29
using v8::HandleScope;
30
using v8::Isolate;
31
using v8::Local;
32
using v8::Object;
33
using v8::Value;
34
35
using v8_inspector::StringBuffer;
36
using v8_inspector::StringView;
37
using v8_inspector::V8Inspector;
38
using v8_inspector::V8InspectorClient;
39
40
static uv_sem_t start_io_thread_semaphore;
41
static uv_async_t start_io_thread_async;
42
43
class StartIoTask : public v8::Task {
44
 public:
45
1
  explicit StartIoTask(Agent* agent) : agent(agent) {}
46
47
  void Run() override {
48
    agent->StartIoThread(false);
49
  }
50
51
 private:
52
  Agent* agent;
53
};
54
55
238
std::unique_ptr<StringBuffer> ToProtocolString(Isolate* isolate,
56
                                               Local<Value> value) {
57
238
  TwoByteValue buffer(isolate, value);
58
238
  return StringBuffer::create(StringView(*buffer, buffer.length()));
59
}
60
61
// Called on the main thread.
62
void StartIoThreadAsyncCallback(uv_async_t* handle) {
63
  static_cast<Agent*>(handle->data)->StartIoThread(false);
64
}
65
66
1
void StartIoInterrupt(Isolate* isolate, void* agent) {
67
1
  static_cast<Agent*>(agent)->StartIoThread(false);
68
1
}
69
70
71
#ifdef __POSIX__
72
1
static void StartIoThreadWakeup(int signo) {
73
1
  uv_sem_post(&start_io_thread_semaphore);
74
1
}
75
76
3290
inline void* StartIoThreadMain(void* unused) {
77
  for (;;) {
78
3290
    uv_sem_wait(&start_io_thread_semaphore);
79
1
    Agent* agent = static_cast<Agent*>(start_io_thread_async.data);
80
1
    if (agent != nullptr)
81
1
      agent->RequestIoThreadStart();
82
1
  }
83
  return nullptr;
84
}
85
86
3289
static int StartDebugSignalHandler() {
87
  // Start a watchdog thread for calling v8::Debug::DebugBreak() because
88
  // it's not safe to call directly from the signal handler, it can
89
  // deadlock with the thread it interrupts.
90
3289
  CHECK_EQ(0, uv_sem_init(&start_io_thread_semaphore, 0));
91
  pthread_attr_t attr;
92
3289
  CHECK_EQ(0, pthread_attr_init(&attr));
93
  // Don't shrink the thread's stack on FreeBSD.  Said platform decided to
94
  // follow the pthreads specification to the letter rather than in spirit:
95
  // https://lists.freebsd.org/pipermail/freebsd-current/2014-March/048885.html
96
#ifndef __FreeBSD__
97
3289
  CHECK_EQ(0, pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN));
98
#endif  // __FreeBSD__
99
3289
  CHECK_EQ(0, pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED));
100
  sigset_t sigmask;
101
  // Mask all signals.
102
3289
  sigfillset(&sigmask);
103
3289
  CHECK_EQ(0, pthread_sigmask(SIG_SETMASK, &sigmask, &sigmask));
104
  pthread_t thread;
105
  const int err = pthread_create(&thread, &attr,
106
3289
                                 StartIoThreadMain, nullptr);
107
  // Restore original mask
108
3289
  CHECK_EQ(0, pthread_sigmask(SIG_SETMASK, &sigmask, nullptr));
109
3289
  CHECK_EQ(0, pthread_attr_destroy(&attr));
110
3289
  if (err != 0) {
111
    fprintf(stderr, "node[%d]: pthread_create: %s\n", getpid(), strerror(err));
112
    fflush(stderr);
113
    // Leave SIGUSR1 blocked.  We don't install a signal handler,
114
    // receiving the signal would terminate the process.
115
    return -err;
116
  }
117
3289
  RegisterSignalHandler(SIGUSR1, StartIoThreadWakeup);
118
  // Unblock SIGUSR1.  A pending SIGUSR1 signal will now be delivered.
119
3289
  sigemptyset(&sigmask);
120
3289
  sigaddset(&sigmask, SIGUSR1);
121
3289
  CHECK_EQ(0, pthread_sigmask(SIG_UNBLOCK, &sigmask, nullptr));
122
3289
  return 0;
123
}
124
#endif  // __POSIX__
125
126
127
#ifdef _WIN32
128
DWORD WINAPI StartIoThreadProc(void* arg) {
129
  Agent* agent = static_cast<Agent*>(start_io_thread_async.data);
130
  if (agent != nullptr)
131
    agent->RequestIoThreadStart();
132
  return 0;
133
}
134
135
static int GetDebugSignalHandlerMappingName(DWORD pid, wchar_t* buf,
136
                                            size_t buf_len) {
137
  return _snwprintf(buf, buf_len, L"node-debug-handler-%u", pid);
138
}
139
140
static int StartDebugSignalHandler() {
141
  wchar_t mapping_name[32];
142
  HANDLE mapping_handle;
143
  DWORD pid;
144
  LPTHREAD_START_ROUTINE* handler;
145
146
  pid = GetCurrentProcessId();
147
148
  if (GetDebugSignalHandlerMappingName(pid,
149
                                       mapping_name,
150
                                       arraysize(mapping_name)) < 0) {
151
    return -1;
152
  }
153
154
  mapping_handle = CreateFileMappingW(INVALID_HANDLE_VALUE,
155
                                      nullptr,
156
                                      PAGE_READWRITE,
157
                                      0,
158
                                      sizeof *handler,
159
                                      mapping_name);
160
  if (mapping_handle == nullptr) {
161
    return -1;
162
  }
163
164
  handler = reinterpret_cast<LPTHREAD_START_ROUTINE*>(
165
      MapViewOfFile(mapping_handle,
166
                    FILE_MAP_ALL_ACCESS,
167
                    0,
168
                    0,
169
                    sizeof *handler));
170
  if (handler == nullptr) {
171
    CloseHandle(mapping_handle);
172
    return -1;
173
  }
174
175
  *handler = StartIoThreadProc;
176
177
  UnmapViewOfFile(static_cast<void*>(handler));
178
179
  return 0;
180
}
181
#endif  // _WIN32
182
183
184
// Used in NodeInspectorClient::currentTimeMS() below.
185
const int NANOS_PER_MSEC = 1000000;
186
const int CONTEXT_GROUP_ID = 1;
187
188
class ChannelImpl final : public v8_inspector::V8Inspector::Channel {
189
 public:
190
19
  explicit ChannelImpl(V8Inspector* inspector,
191
                       InspectorSessionDelegate* delegate)
192
19
                       : delegate_(delegate) {
193
19
    session_ = inspector->connect(1, this, StringView());
194
19
  }
195
196
38
  virtual ~ChannelImpl() {}
197
198
117
  void dispatchProtocolMessage(const StringView& message) {
199
117
    session_->dispatchProtocolMessage(message);
200
117
  }
201
202
56
  bool waitForFrontendMessage() {
203
56
    return delegate_->WaitForFrontendMessageWhilePaused();
204
  }
205
206
9
  void schedulePauseOnNextStatement(const std::string& reason) {
207
9
    std::unique_ptr<StringBuffer> buffer = Utf8ToStringView(reason);
208
9
    session_->schedulePauseOnNextStatement(buffer->string(), buffer->string());
209
9
  }
210
211
40
  InspectorSessionDelegate* delegate() {
212
40
    return delegate_;
213
  }
214
215
 private:
216
117
  void sendResponse(
217
      int callId,
218
      std::unique_ptr<v8_inspector::StringBuffer> message) override {
219
117
    sendMessageToFrontend(message->string());
220
117
  }
221
222
1307
  void sendNotification(
223
      std::unique_ptr<v8_inspector::StringBuffer> message) override {
224
1307
    sendMessageToFrontend(message->string());
225
1307
  }
226
227
23
  void flushProtocolNotifications() override { }
228
229
1424
  void sendMessageToFrontend(const StringView& message) {
230
1424
    delegate_->SendMessageToFrontend(message);
231
1424
  }
232
233
  InspectorSessionDelegate* const delegate_;
234
  std::unique_ptr<v8_inspector::V8InspectorSession> session_;
235
};
236
237
class InspectorTimer {
238
 public:
239
  InspectorTimer(uv_loop_t* loop,
240
                 double interval_s,
241
                 V8InspectorClient::TimerCallback callback,
242
                 void* data) : timer_(),
243
                               callback_(callback),
244
                               data_(data) {
245
    uv_timer_init(loop, &timer_);
246
    int64_t interval_ms = 1000 * interval_s;
247
    uv_timer_start(&timer_, OnTimer, interval_ms, interval_ms);
248
  }
249
250
  InspectorTimer(const InspectorTimer&) = delete;
251
252
  void Stop() {
253
    uv_timer_stop(&timer_);
254
    uv_close(reinterpret_cast<uv_handle_t*>(&timer_), TimerClosedCb);
255
  }
256
257
 private:
258
  static void OnTimer(uv_timer_t* uvtimer) {
259
    InspectorTimer* timer = node::ContainerOf(&InspectorTimer::timer_, uvtimer);
260
    timer->callback_(timer->data_);
261
  }
262
263
  static void TimerClosedCb(uv_handle_t* uvtimer) {
264
    std::unique_ptr<InspectorTimer> timer(
265
        node::ContainerOf(&InspectorTimer::timer_,
266
                          reinterpret_cast<uv_timer_t*>(uvtimer)));
267
    // Unique_ptr goes out of scope here and pointer is deleted.
268
  }
269
270
  ~InspectorTimer() {}
271
272
  uv_timer_t timer_;
273
  V8InspectorClient::TimerCallback callback_;
274
  void* data_;
275
276
  friend std::unique_ptr<InspectorTimer>::deleter_type;
277
};
278
279
class InspectorTimerHandle {
280
 public:
281
  InspectorTimerHandle(uv_loop_t* loop, double interval_s,
282
                       V8InspectorClient::TimerCallback callback, void* data) {
283
    timer_ = new InspectorTimer(loop, interval_s, callback, data);
284
  }
285
286
  InspectorTimerHandle(const InspectorTimerHandle&) = delete;
287
288
  ~InspectorTimerHandle() {
289
    CHECK_NE(timer_, nullptr);
290
    timer_->Stop();
291
    timer_ = nullptr;
292
  }
293
 private:
294
  InspectorTimer* timer_;
295
};
296
}  // namespace
297
298
5892
class NodeInspectorClient : public V8InspectorClient {
299
 public:
300
3289
  NodeInspectorClient(node::Environment* env, node::NodePlatform* platform)
301
      : env_(env), platform_(platform), terminated_(false),
302
3289
        running_nested_loop_(false) {
303
3289
    client_ = V8Inspector::create(env->isolate(), this);
304
3289
    contextCreated(env->context(), "Node.js Main Context");
305
3289
  }
306
307
40
  void runMessageLoopOnPause(int context_group_id) override {
308
40
    CHECK_NE(channel_, nullptr);
309
40
    if (running_nested_loop_)
310
40
      return;
311
40
    terminated_ = false;
312
40
    running_nested_loop_ = true;
313

125
    while (!terminated_ && channel_->waitForFrontendMessage()) {
314
45
      platform_->FlushForegroundTasks(env_->isolate());
315
    }
316
40
    terminated_ = false;
317
40
    running_nested_loop_ = false;
318
  }
319
320
165
  double currentTimeMS() override {
321
165
    return uv_hrtime() * 1.0 / NANOS_PER_MSEC;
322
  }
323
324
10
  void maxAsyncCallStackDepthChanged(int depth) override {
325
10
    if (depth == 0) {
326
5
      env_->inspector_agent()->DisableAsyncHook();
327
    } else {
328
5
      env_->inspector_agent()->EnableAsyncHook();
329
    }
330
10
  }
331
332
3570
  void contextCreated(Local<Context> context, const std::string& name) {
333
3570
    std::unique_ptr<StringBuffer> name_buffer = Utf8ToStringView(name);
334
    v8_inspector::V8ContextInfo info(context, CONTEXT_GROUP_ID,
335
3570
                                     name_buffer->string());
336
3570
    client_->contextCreated(info);
337
3570
  }
338
339
127
  void contextDestroyed(Local<Context> context) {
340
127
    client_->contextDestroyed(context);
341
127
  }
342
343
38
  void quitMessageLoopOnPause() override {
344
38
    terminated_ = true;
345
38
  }
346
347
19
  void connectFrontend(InspectorSessionDelegate* delegate) {
348
19
    CHECK_EQ(channel_, nullptr);
349
57
    channel_ = std::unique_ptr<ChannelImpl>(
350
57
        new ChannelImpl(client_.get(), delegate));
351
19
  }
352
353
18
  void disconnectFrontend() {
354
18
    quitMessageLoopOnPause();
355
18
    channel_.reset();
356
18
  }
357
358
117
  void dispatchMessageFromFrontend(const StringView& message) {
359
117
    CHECK_NE(channel_, nullptr);
360
117
    channel_->dispatchProtocolMessage(message);
361
117
  }
362
363
10
  Local<Context> ensureDefaultContextInGroup(int contextGroupId) override {
364
10
    return env_->context();
365
  }
366
367
2
  void installAdditionalCommandLineAPI(Local<Context> context,
368
                                       Local<Object> target) override {
369
2
    Local<Object> console_api = env_->inspector_console_api_object();
370
371
    Local<Array> properties =
372
4
        console_api->GetOwnPropertyNames(context).ToLocalChecked();
373
8
    for (uint32_t i = 0; i < properties->Length(); ++i) {
374
4
      Local<Value> key = properties->Get(context, i).ToLocalChecked();
375
      target->Set(context,
376
                  key,
377
6
                  console_api->Get(context, key).ToLocalChecked()).FromJust();
378
    }
379
2
  }
380
381
119
  void FatalException(Local<Value> error, Local<v8::Message> message) {
382
119
    Local<Context> context = env_->context();
383
384
357
    int script_id = message->GetScriptOrigin().ScriptID()->Value();
385
386
119
    Local<v8::StackTrace> stack_trace = message->GetStackTrace();
387
388

476
    if (!stack_trace.IsEmpty() &&
389

241
        stack_trace->GetFrameCount() > 0 &&
390
122
        script_id == stack_trace->GetFrame(0)->GetScriptId()) {
391
1
      script_id = 0;
392
    }
393
394
119
    const uint8_t DETAILS[] = "Uncaught";
395
396
119
    Isolate* isolate = context->GetIsolate();
397
398
119
    client_->exceptionThrown(
399
        context,
400
        StringView(DETAILS, sizeof(DETAILS) - 1),
401
        error,
402
357
        ToProtocolString(isolate, message->Get())->string(),
403
238
        ToProtocolString(isolate, message->GetScriptResourceName())->string(),
404
476
        message->GetLineNumber(context).FromMaybe(0),
405
476
        message->GetStartColumn(context).FromMaybe(0),
406
119
        client_->createStackTrace(stack_trace),
407
714
        script_id);
408
119
  }
409
410
58
  ChannelImpl* channel() {
411
58
    return channel_.get();
412
  }
413
414
  void startRepeatingTimer(double interval_s,
415
                           TimerCallback callback,
416
                           void* data) override {
417
    timers_.emplace(std::piecewise_construct, std::make_tuple(data),
418
                    std::make_tuple(env_->event_loop(), interval_s, callback,
419
                                    data));
420
  }
421
422
  void cancelTimer(void* data) override {
423
    timers_.erase(data);
424
  }
425
426
  // Async stack traces instrumentation.
427
13
  void AsyncTaskScheduled(const StringView& task_name, void* task,
428
                          bool recurring) {
429
13
    client_->asyncTaskScheduled(task_name, task, recurring);
430
13
  }
431
432
2
  void AsyncTaskCanceled(void* task) {
433
2
    client_->asyncTaskCanceled(task);
434
2
  }
435
436
7
  void AsyncTaskStarted(void* task) {
437
7
    client_->asyncTaskStarted(task);
438
7
  }
439
440
4
  void AsyncTaskFinished(void* task) {
441
4
    client_->asyncTaskFinished(task);
442
4
  }
443
444
  void AllAsyncTasksCanceled() {
445
    client_->allAsyncTasksCanceled();
446
  }
447
448
 private:
449
  node::Environment* env_;
450
  node::NodePlatform* platform_;
451
  bool terminated_;
452
  bool running_nested_loop_;
453
  std::unique_ptr<V8Inspector> client_;
454
  std::unique_ptr<ChannelImpl> channel_;
455
  std::unordered_map<void*, InspectorTimerHandle> timers_;
456
};
457
458
3293
Agent::Agent(Environment* env) : parent_env_(env),
459
                                 client_(nullptr),
460
                                 platform_(nullptr),
461
                                 enabled_(false),
462
                                 next_context_number_(1),
463
                                 pending_enable_async_hook_(false),
464
9879
                                 pending_disable_async_hook_(false) {}
465
466
// Destructor needs to be defined here in implementation file as the header
467
// does not have full definition of some classes.
468
2950
Agent::~Agent() {
469
2950
}
470
471
3289
bool Agent::Start(node::NodePlatform* platform, const char* path,
472
                  const DebugOptions& options) {
473
3289
  path_ = path == nullptr ? "" : path;
474
3289
  debug_options_ = options;
475
9867
  client_ =
476
      std::unique_ptr<NodeInspectorClient>(
477
6578
          new NodeInspectorClient(parent_env_, platform));
478
3289
  platform_ = platform;
479
3289
  CHECK_EQ(0, uv_async_init(uv_default_loop(),
480
                            &start_io_thread_async,
481
                            StartIoThreadAsyncCallback));
482
3289
  start_io_thread_async.data = this;
483
3289
  uv_unref(reinterpret_cast<uv_handle_t*>(&start_io_thread_async));
484
485
  // Ignore failure, SIGUSR1 won't work, but that should not block node start.
486
3289
  StartDebugSignalHandler();
487
3289
  if (options.inspector_enabled()) {
488
    // This will return false if listen failed on the inspector port.
489
64
    return StartIoThread(options.wait_for_connect());
490
  }
491
3225
  return true;
492
}
493
494
68
bool Agent::StartIoThread(bool wait_for_connect) {
495
68
  if (io_ != nullptr)
496
1
    return true;
497
498
67
  CHECK_NE(client_, nullptr);
499
500
67
  enabled_ = true;
501
201
  io_ = std::unique_ptr<InspectorIo>(
502
      new InspectorIo(parent_env_, platform_, path_, debug_options_,
503
134
                      wait_for_connect));
504
67
  if (!io_->Start()) {
505
2
    client_.reset();
506
2
    return false;
507
  }
508
509
65
  v8::Isolate* isolate = parent_env_->isolate();
510
65
  HandleScope handle_scope(isolate);
511
65
  auto context = parent_env_->context();
512
513
  // Send message to enable debug in workers
514
65
  Local<Object> process_object = parent_env_->process_object();
515
  Local<Value> emit_fn =
516
195
      process_object->Get(context, FIXED_ONE_BYTE_STRING(isolate, "emit"))
517
130
          .ToLocalChecked();
518
  // In case the thread started early during the startup
519
65
  if (!emit_fn->IsFunction())
520
62
    return true;
521
522
3
  Local<Object> message = Object::New(isolate);
523
  message->Set(context, FIXED_ONE_BYTE_STRING(isolate, "cmd"),
524
12
               FIXED_ONE_BYTE_STRING(isolate, "NODE_DEBUG_ENABLED")).FromJust();
525
  Local<Value> argv[] = {
526
    FIXED_ONE_BYTE_STRING(isolate, "internalMessage"),
527
    message
528
9
  };
529
  MakeCallback(parent_env_->isolate(), process_object, emit_fn.As<Function>(),
530
6
               arraysize(argv), argv, {0, 0});
531
532
3
  return true;
533
}
534
535
6
void Agent::Stop() {
536
6
  if (io_ != nullptr) {
537
4
    io_->Stop();
538
4
    io_.reset();
539
4
    enabled_ = false;
540
  }
541
6
}
542
543
19
void Agent::Connect(InspectorSessionDelegate* delegate) {
544
19
  enabled_ = true;
545
19
  client_->connectFrontend(delegate);
546
19
}
547
548
3160
bool Agent::IsConnected() {
549

3160
  return io_ && io_->IsConnected();
550
}
551
552
127
void Agent::WaitForDisconnect() {
553
127
  CHECK_NE(client_, nullptr);
554
127
  client_->contextDestroyed(parent_env_->context());
555
127
  if (io_ != nullptr) {
556
12
    io_->WaitForDisconnect();
557
  }
558
127
}
559
560
119
void Agent::FatalException(Local<Value> error, Local<v8::Message> message) {
561
119
  if (!IsStarted())
562
119
    return;
563
119
  client_->FatalException(error, message);
564
119
  WaitForDisconnect();
565
}
566
567
117
void Agent::Dispatch(const StringView& message) {
568
117
  CHECK_NE(client_, nullptr);
569
117
  client_->dispatchMessageFromFrontend(message);
570
117
}
571
572
18
void Agent::Disconnect() {
573
18
  CHECK_NE(client_, nullptr);
574
18
  client_->disconnectFrontend();
575
18
}
576
577
9
void Agent::RunMessageLoop() {
578
9
  CHECK_NE(client_, nullptr);
579
9
  client_->runMessageLoopOnPause(CONTEXT_GROUP_ID);
580
9
}
581
582
49
InspectorSessionDelegate* Agent::delegate() {
583
49
  CHECK_NE(client_, nullptr);
584
49
  ChannelImpl* channel = client_->channel();
585
49
  if (channel == nullptr)
586
9
    return nullptr;
587
40
  return channel->delegate();
588
}
589
590
9
void Agent::PauseOnNextJavascriptStatement(const std::string& reason) {
591
9
  ChannelImpl* channel = client_->channel();
592
9
  if (channel != nullptr)
593
9
    channel->schedulePauseOnNextStatement(reason);
594
9
}
595
596
3287
void Agent::RegisterAsyncHook(Isolate* isolate,
597
                              v8::Local<v8::Function> enable_function,
598
                              v8::Local<v8::Function> disable_function) {
599
3287
  enable_async_hook_function_.Reset(isolate, enable_function);
600
3287
  disable_async_hook_function_.Reset(isolate, disable_function);
601
3287
  if (pending_enable_async_hook_) {
602
2
    CHECK(!pending_disable_async_hook_);
603
2
    pending_enable_async_hook_ = false;
604
2
    EnableAsyncHook();
605
3285
  } else if (pending_disable_async_hook_) {
606
    CHECK(!pending_enable_async_hook_);
607
    pending_disable_async_hook_ = false;
608
    DisableAsyncHook();
609
  }
610
3287
}
611
612
7
void Agent::EnableAsyncHook() {
613
14
  if (!enable_async_hook_function_.IsEmpty()) {
614
5
    Isolate* isolate = parent_env_->isolate();
615
10
    ToggleAsyncHook(isolate, enable_async_hook_function_.Get(isolate));
616
2
  } else if (pending_disable_async_hook_) {
617
    CHECK(!pending_enable_async_hook_);
618
    pending_disable_async_hook_ = false;
619
  } else {
620
2
    pending_enable_async_hook_ = true;
621
  }
622
7
}
623
624
5
void Agent::DisableAsyncHook() {
625
10
  if (!disable_async_hook_function_.IsEmpty()) {
626
5
    Isolate* isolate = parent_env_->isolate();
627
10
    ToggleAsyncHook(isolate, disable_async_hook_function_.Get(isolate));
628
  } else if (pending_enable_async_hook_) {
629
    CHECK(!pending_disable_async_hook_);
630
    pending_enable_async_hook_ = false;
631
  } else {
632
    pending_disable_async_hook_ = true;
633
  }
634
5
}
635
636
10
void Agent::ToggleAsyncHook(Isolate* isolate, Local<Function> fn) {
637
10
  HandleScope handle_scope(isolate);
638
10
  auto context = parent_env_->context();
639
10
  auto result = fn->Call(context, Undefined(isolate), 0, nullptr);
640
10
  if (result.IsEmpty()) {
641
    FatalError(
642
        "node::inspector::Agent::ToggleAsyncHook",
643
        "Cannot toggle Inspector's AsyncHook, please report this.");
644
10
  }
645
10
}
646
647
13
void Agent::AsyncTaskScheduled(const StringView& task_name, void* task,
648
                               bool recurring) {
649
13
  client_->AsyncTaskScheduled(task_name, task, recurring);
650
13
}
651
652
2
void Agent::AsyncTaskCanceled(void* task) {
653
2
  client_->AsyncTaskCanceled(task);
654
2
}
655
656
7
void Agent::AsyncTaskStarted(void* task) {
657
7
  client_->AsyncTaskStarted(task);
658
7
}
659
660
4
void Agent::AsyncTaskFinished(void* task) {
661
4
  client_->AsyncTaskFinished(task);
662
4
}
663
664
void Agent::AllAsyncTasksCanceled() {
665
  client_->AllAsyncTasksCanceled();
666
}
667
668
1
void Agent::RequestIoThreadStart() {
669
  // We need to attempt to interrupt V8 flow (in case Node is running
670
  // continuous JS code) and to wake up libuv thread (in case Node is waiting
671
  // for IO events)
672
1
  uv_async_send(&start_io_thread_async);
673
1
  v8::Isolate* isolate = parent_env_->isolate();
674
1
  platform_->CallOnForegroundThread(isolate, new StartIoTask(this));
675
1
  isolate->RequestInterrupt(StartIoInterrupt, this);
676
1
  uv_async_send(&start_io_thread_async);
677
1
}
678
679
3574
void Agent::ContextCreated(Local<Context> context) {
680
3574
  if (client_ == nullptr)  // This happens for a main context
681
6867
    return;
682
281
  std::ostringstream name;
683
281
  name << "VM Context " << next_context_number_++;
684
281
  client_->contextCreated(context, name.str());
685
}
686
687
3287
bool Agent::IsWaitingForConnect() {
688
3287
  return debug_options_.wait_for_connect();
689
}
690
691
}  // namespace inspector
692
}  // namespace node
693