v8从入门到入土:调试篇三(Inspector)

466 阅读1分钟

首先,还想提下 console 这个对象(因为我们在这个模块上走了些弯路)。

正常来说 console 这个对象对于v8嵌入式来说没什么用,我们刚开始都认为V8不带这个对象,在 nodejs/chromium 中是外层注入的。后来才发现其实V8默认也会带这个对象,但仅当在 inspector 链接调试的时候才会起作用,它会通过 inspect 协议把 console 的内容发送到 CDT 中,然后你就可以像H5一样愉快的使用 console 了。PS:JavascriptCore 在 console 这个点上跟V8是一致的。

接下来说下这篇文章的主题,断点调试。 可能有的人会问,前面不是已经实现了inspect协议了吗?为什么还要自己实现调试呢?其实v8这里的处理是比较绕的,需要业务自己实现几个虚方法,最核心的是runMessageLoopOnPause和quitMessageLoopOnPause。

runMessageLoopOnPause,当CDT被触发断点时就会调用该方法,这时需要业务自己去加锁阻塞线程,并同时继续处理由CDT发送过来的消息,直到quitMessageLoopOnPause被触发,恢复线程,这样才能做到断点调试。

void V8InspectorClientImpl::runMessageLoopOnPause(int contextGroupId) {
  std::shared_ptr<Engine> engine = V8ChannelImpl::runtime_->pEngine.lock();
  if (engine) {
    engine->jsRunner()->pauseThreadForInspector();
  }
}

void V8InspectorClientImpl::quitMessageLoopOnPause() {
  std::shared_ptr<Engine> engine = V8ChannelImpl::runtime_->pEngine.lock();
  if (engine) {
    engine->jsRunner()->resumeThreadForInspector();
  }
}
 

void JavaScriptTaskRunner::pauseThreadForInspector() {
  m_isInspectorCallPause = true;

  while (m_isInspectorCallPause) {
    std::shared_ptr<hippy::base::Task> task = GetNext();
    if (task == nullptr) {
      return;
    }

    if (task->canceled_ == false) {
      task->Run();
    }
  }
}

void JavaScriptTaskRunner::resumeThreadForInspector() {
  m_isInspectorCallPause = false;
}
 

std::shared_ptr<Task> TaskRunner::GetNext() {
  std::unique_lock<std::mutex> lock(m_mutex);

  for (;;) {
    DelayedTimeInMs now = MonotonicallyIncreasingTime();
    std::shared_ptr<Task> task = popTaskFromDelayedQueueNoLock(now);
    while (task) {
      postTaskNoLock(std::move(task));
      task = popTaskFromDelayedQueueNoLock(now);
    }

    if (!task_queue_.empty()) {
      std::shared_ptr<Task> result = std::move(task_queue_.front());
      task_queue_.pop();
      return result;
    }

    if (is_terminated_) {
      m_cv.notify_all();
      return nullptr;
    }

    if (task_queue_.empty() && !delayed_task_queue_.empty()) {
      const DelayedEntry& delayed_task = delayed_task_queue_.top();
      DelayedTimeInMs wait_in_msseconds = delayed_task.first - now;
      bool notified =
          m_cv.wait_for(lock, std::chrono::milliseconds(wait_in_msseconds)) ==
          std::cv_status::timeout;
      HIPPY_USE(notified);
    } else {
      m_cv.wait(lock);
    }
  }
}