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: 290 334 86.8 %
Date: 2017-12-18 Branches: 73 118 61.9 %

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

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

472
    if (!stack_trace.IsEmpty() &&
394

239
        stack_trace->GetFrameCount() > 0 &&
395
121
        script_id == stack_trace->GetFrame(0)->GetScriptId()) {
396
1
      script_id = 0;
397
    }
398
399
118
    const uint8_t DETAILS[] = "Uncaught";
400
401
118
    Isolate* isolate = context->GetIsolate();
402
403
118
    client_->exceptionThrown(
404
        context,
405
        StringView(DETAILS, sizeof(DETAILS) - 1),
406
        error,
407
354
        ToProtocolString(isolate, message->Get())->string(),
408
236
        ToProtocolString(isolate, message->GetScriptResourceName())->string(),
409
472
        message->GetLineNumber(context).FromMaybe(0),
410
472
        message->GetStartColumn(context).FromMaybe(0),
411
118
        client_->createStackTrace(stack_trace),
412
708
        script_id);
413
118
  }
414
415
3295
  ChannelImpl* channel() {
416
3295
    return channel_.get();
417
  }
418
419
  void startRepeatingTimer(double interval_s,
420
                           TimerCallback callback,
421
                           void* data) override {
422
    timers_.emplace(std::piecewise_construct, std::make_tuple(data),
423
                    std::make_tuple(env_->event_loop(), interval_s, callback,
424
                                    data));
425
  }
426
427
  void cancelTimer(void* data) override {
428
    timers_.erase(data);
429
  }
430
431
  // Async stack traces instrumentation.
432
8
  void AsyncTaskScheduled(const StringView& task_name, void* task,
433
                          bool recurring) {
434
8
    client_->asyncTaskScheduled(task_name, task, recurring);
435
8
  }
436
437
2
  void AsyncTaskCanceled(void* task) {
438
2
    client_->asyncTaskCanceled(task);
439
2
  }
440
441
5
  void AsyncTaskStarted(void* task) {
442
5
    client_->asyncTaskStarted(task);
443
5
  }
444
445
2
  void AsyncTaskFinished(void* task) {
446
2
    client_->asyncTaskFinished(task);
447
2
  }
448
449
  void AllAsyncTasksCanceled() {
450
    client_->allAsyncTasksCanceled();
451
  }
452
453
 private:
454
  node::Environment* env_;
455
  node::NodePlatform* platform_;
456
  bool terminated_;
457
  bool running_nested_loop_;
458
  std::unique_ptr<V8Inspector> client_;
459
  std::unique_ptr<ChannelImpl> channel_;
460
  std::unordered_map<void*, InspectorTimerHandle> timers_;
461
};
462
463
3352
Agent::Agent(Environment* env) : parent_env_(env),
464
                                 client_(nullptr),
465
                                 platform_(nullptr),
466
                                 enabled_(false),
467
                                 next_context_number_(1),
468
                                 pending_enable_async_hook_(false),
469
10056
                                 pending_disable_async_hook_(false) {}
470
471
// Destructor needs to be defined here in implementation file as the header
472
// does not have full definition of some classes.
473
3007
Agent::~Agent() {
474
3007
}
475
476
3348
bool Agent::Start(node::NodePlatform* platform, const char* path,
477
                  const DebugOptions& options) {
478
3348
  path_ = path == nullptr ? "" : path;
479
3348
  debug_options_ = options;
480
10044
  client_ =
481
      std::unique_ptr<NodeInspectorClient>(
482
6696
          new NodeInspectorClient(parent_env_, platform));
483
3348
  platform_ = platform;
484
3348
  CHECK_EQ(0, uv_async_init(uv_default_loop(),
485
                            &start_io_thread_async,
486
                            StartIoThreadAsyncCallback));
487
3348
  start_io_thread_async.data = this;
488
3348
  uv_unref(reinterpret_cast<uv_handle_t*>(&start_io_thread_async));
489
490
  // Ignore failure, SIGUSR1 won't work, but that should not block node start.
491
3348
  StartDebugSignalHandler();
492
3348
  if (options.inspector_enabled()) {
493
    // This will return false if listen failed on the inspector port.
494
59
    return StartIoThread(options.wait_for_connect());
495
  }
496
3289
  return true;
497
}
498
499
65
bool Agent::StartIoThread(bool wait_for_connect) {
500
65
  if (io_ != nullptr)
501
3
    return true;
502
503
62
  CHECK_NE(client_, nullptr);
504
505
62
  enabled_ = true;
506
186
  io_ = std::unique_ptr<InspectorIo>(
507
      new InspectorIo(parent_env_, platform_, path_, debug_options_,
508
124
                      wait_for_connect));
509
62
  if (!io_->Start()) {
510
    client_.reset();
511
    return false;
512
  }
513
514
62
  v8::Isolate* isolate = parent_env_->isolate();
515
62
  HandleScope handle_scope(isolate);
516
62
  auto context = parent_env_->context();
517
518
  // Send message to enable debug in workers
519
62
  Local<Object> process_object = parent_env_->process_object();
520
  Local<Value> emit_fn =
521
186
      process_object->Get(context, FIXED_ONE_BYTE_STRING(isolate, "emit"))
522
124
          .ToLocalChecked();
523
  // In case the thread started early during the startup
524
62
  if (!emit_fn->IsFunction())
525
59
    return true;
526
527
3
  Local<Object> message = Object::New(isolate);
528
  message->Set(context, FIXED_ONE_BYTE_STRING(isolate, "cmd"),
529
12
               FIXED_ONE_BYTE_STRING(isolate, "NODE_DEBUG_ENABLED")).FromJust();
530
  Local<Value> argv[] = {
531
    FIXED_ONE_BYTE_STRING(isolate, "internalMessage"),
532
    message
533
9
  };
534
  MakeCallback(parent_env_->isolate(), process_object, emit_fn.As<Function>(),
535
6
               arraysize(argv), argv, {0, 0});
536
537
3
  return true;
538
}
539
540
6
void Agent::Stop() {
541
6
  if (io_ != nullptr) {
542
4
    io_->Stop();
543
4
    io_.reset();
544
4
    enabled_ = false;
545
  }
546
6
}
547
548
21
void Agent::Connect(InspectorSessionDelegate* delegate) {
549
21
  enabled_ = true;
550
21
  client_->connectFrontend(delegate);
551
21
}
552
553
129
void Agent::WaitForDisconnect() {
554
129
  CHECK_NE(client_, nullptr);
555
129
  client_->contextDestroyed(parent_env_->context());
556
129
  if (io_ != nullptr) {
557
13
    io_->WaitForDisconnect();
558
  }
559
129
}
560
561
118
void Agent::FatalException(Local<Value> error, Local<v8::Message> message) {
562
118
  if (!IsStarted())
563
118
    return;
564
118
  client_->FatalException(error, message);
565
118
  WaitForDisconnect();
566
}
567
568
119
void Agent::Dispatch(const StringView& message) {
569
119
  CHECK_NE(client_, nullptr);
570
119
  client_->dispatchMessageFromFrontend(message);
571
119
}
572
573
18
void Agent::Disconnect() {
574
18
  CHECK_NE(client_, nullptr);
575
18
  client_->disconnectFrontend();
576
18
}
577
578
9
void Agent::RunMessageLoop() {
579
9
  CHECK_NE(client_, nullptr);
580
9
  client_->runMessageLoopOnPause(CONTEXT_GROUP_ID);
581
9
}
582
583
3286
InspectorSessionDelegate* Agent::delegate() {
584
3286
  CHECK_NE(client_, nullptr);
585
3286
  ChannelImpl* channel = client_->channel();
586
3286
  if (channel == nullptr)
587
3232
    return nullptr;
588
54
  return channel->delegate();
589
}
590
591
9
void Agent::PauseOnNextJavascriptStatement(const std::string& reason) {
592
9
  ChannelImpl* channel = client_->channel();
593
9
  if (channel != nullptr)
594
9
    channel->schedulePauseOnNextStatement(reason);
595
9
}
596
597
3349
void Agent::RegisterAsyncHook(Isolate* isolate,
598
                              v8::Local<v8::Function> enable_function,
599
                              v8::Local<v8::Function> disable_function) {
600
3349
  enable_async_hook_function_.Reset(isolate, enable_function);
601
3349
  disable_async_hook_function_.Reset(isolate, disable_function);
602
3349
  if (pending_enable_async_hook_) {
603
2
    CHECK(!pending_disable_async_hook_);
604
2
    pending_enable_async_hook_ = false;
605
2
    EnableAsyncHook();
606
3347
  } else if (pending_disable_async_hook_) {
607
    CHECK(!pending_enable_async_hook_);
608
    pending_disable_async_hook_ = false;
609
    DisableAsyncHook();
610
  }
611
3349
}
612
613
8
void Agent::EnableAsyncHook() {
614
16
  if (!enable_async_hook_function_.IsEmpty()) {
615
6
    ToggleAsyncHook(parent_env_->isolate(), enable_async_hook_function_);
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
8
}
623
624
5
void Agent::DisableAsyncHook() {
625
10
  if (!disable_async_hook_function_.IsEmpty()) {
626
5
    ToggleAsyncHook(parent_env_->isolate(), disable_async_hook_function_);
627
  } else if (pending_enable_async_hook_) {
628
    CHECK(!pending_disable_async_hook_);
629
    pending_enable_async_hook_ = false;
630
  } else {
631
    pending_disable_async_hook_ = true;
632
  }
633
5
}
634
635
11
void Agent::ToggleAsyncHook(Isolate* isolate, const Persistent<Function>& fn) {
636
11
  HandleScope handle_scope(isolate);
637
22
  CHECK(!fn.IsEmpty());
638
11
  auto context = parent_env_->context();
639
33
  auto result = fn.Get(isolate)->Call(context, Undefined(isolate), 0, nullptr);
640
11
  if (result.IsEmpty()) {
641
    FatalError(
642
        "node::inspector::Agent::ToggleAsyncHook",
643
        "Cannot toggle Inspector's AsyncHook, please report this.");
644
11
  }
645
11
}
646
647
8
void Agent::AsyncTaskScheduled(const StringView& task_name, void* task,
648
                               bool recurring) {
649
8
  client_->AsyncTaskScheduled(task_name, task, recurring);
650
8
}
651
652
2
void Agent::AsyncTaskCanceled(void* task) {
653
2
  client_->AsyncTaskCanceled(task);
654
2
}
655
656
5
void Agent::AsyncTaskStarted(void* task) {
657
5
  client_->AsyncTaskStarted(task);
658
5
}
659
660
2
void Agent::AsyncTaskFinished(void* task) {
661
2
  client_->AsyncTaskFinished(task);
662
2
}
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
3636
void Agent::ContextCreated(Local<Context> context) {
680
3636
  if (client_ == nullptr)  // This happens for a main context
681
6988
    return;
682
284
  std::ostringstream name;
683
284
  name << "VM Context " << next_context_number_++;
684
284
  client_->contextCreated(context, name.str());
685
}
686
687
3348
bool Agent::IsWaitingForConnect() {
688
3348
  return debug_options_.wait_for_connect();
689
}
690
691
}  // namespace inspector
692
}  // namespace node