深入V8引擎-初始化默認Platform


  本來尋思着寫一篇"'Hello' + ', World'"是怎么從JS代碼編譯然后輸出的,然而compile過程的復雜性遠超我的想象,強上怕會走火入魔,還是老老實實先回家種田,找點咸魚方法先寫着。雖然說是咸魚方法,但是V8任何一塊拿出來都不簡單,之前講的Time模塊說實話大概是屬於源碼里面幼兒園級別的,這次試試難一點的。

  V8的源碼在本地編譯完成后,會提供一個hello-world.cc的sample,里面有新手用戶標准的初始化流程,如下。

int main(int argc, char* argv[]) {
  // Initialize V8.
  // 這個方法在mac不作為
  v8::V8::InitializeICUDefaultLocation(argv[0]);
  // 讀取指定名稱的配置文件 也不用鳥
  v8::V8::InitializeExternalStartupData(argv[0]);
  // 生成一個默認的platform對象
  std::unique_ptr<v8::Platform> platform = v8::platform::NewDefaultPlatform();
  // 初始化剛才的platform
  v8::V8::InitializePlatform(platform.get());
  // V8的初始化
  v8::V8::Initialize();

  // ...
}

  前兩步不用去管,在入門階段用不上。

  第三步是主要內容,探究生成的默認platform對象(當然也可以選擇自己定制一個platform對象),這個類主要負責管理線程池、調用棧、事件隊列等一些雜活。

  這一篇不會去深入方法一步一步走,里面內容太過於雜亂,跳來跳去的,先整體介紹一下所有涉及的類,有一個初步的印象(建議深入閱讀所有基類的英文注釋,解釋的很明白)。

 

Platform

  首先當然是核心類Platform,但這是一個基類,里面的大部分方法都是虛函數。

/**
 * V8 Platform abstraction layer.
 *
 * The embedder has to provide an implementation of this interface before
 * initializing the rest of V8.
 */
class Platform {};

  如果需要定制platform來初始化V8,需要繼承這個類並實現那些方法。一般情況下當然可以V8默認提供的類,即DefaultPlatform。

class DefaultPlatform : public Platform {
  public:
    // 接受一個枚舉值、一個TracingController類的構造函數
    explicit DefaultPlatform(
      IdleTaskSupport idle_task_support = IdleTaskSupport::kDisabled,
      std::unique_ptr<v8::TracingController> tracing_controller = {});
    ~DefaultPlatform() override;
    // 設置線程池大小
    void SetThreadPoolSize(int thread_pool_size);
    // 初始化線程池、管理線程任務相關的方法
    void EnsureBackgroundTaskRunnerInitialized();
  private:
    // 最大線程池數量 默認為8
    static const int kMaxThreadPoolSize;

    int thread_pool_size_;
    IdleTaskSupport idle_task_support_;
    // 線程任務啟動器
    std::shared_ptr<DefaultWorkerThreadsTaskRunner> worker_threads_task_runner_;
    // 工具類
    std::unique_ptr<TracingController> tracing_controller_;
    std::unique_ptr<PageAllocator> page_allocator_;
    // 計數方法 用的是之前介紹的Time模塊
    TimeFunction time_function_for_testing_;
};

/**
 * V8 Tracing controller.
 *
 * Can be implemented by an embedder to record trace events from V8.
 */
class TracingController {};

/**
 * A V8 memory page allocator.
 *
 * Can be implemented by an embedder to manage large host OS allocations.
 */
class PageAllocator {};

  只選了一些初始化相關的方法,其實內容遠比這個要多。其中還定義了兩個類似於Platform的基類變量,一個負責調用棧追蹤,一個負責內存管理。

 

TaskRunner/Thread

  接下來是任務執行者、線程,因為這兩者基本上成對出現,所以放一起來看。

// Thread
//
// Thread objects are used for creating and running threads. When the start()
// method is called the new thread starts running the run() method in the new
// thread. The Thread object should not be deallocated before the thread has
// terminated.

class V8_BASE_EXPORT Thread {
  public:
    // Start new thread by calling the Run() method on the new thread.
    void Start();
    // ...
};

  這是最基礎的Thread,其中定義並實現了Start等常規方法,也有一些虛函數需要繼承去重新實現,除此之外還有一些靜態方法。默認情況下,V8實現了一個類繼承於Thread,位置十分的隱蔽,在默認TaskRunner的private里面。

/**
 * A TaskRunner allows scheduling of tasks. The TaskRunner may still be used to
 * post tasks after the isolate gets destructed, but these tasks may not get
 * executed anymore. All tasks posted to a given TaskRunner will be invoked in
 * sequence. Tasks can be posted from any thread.
 */
class TaskRunner {};

class DefaultWorkerThreadsTaskRunner : public TaskRunner {
  public:
    using TimeFunction = double (*)();
    DefaultWorkerThreadsTaskRunner(uint32_t thread_pool_size, TimeFunction time_function);
  private:
    class WorkerThread : public Thread {
    public:
      explicit WorkerThread(DefaultWorkerThreadsTaskRunner* runner);
      ~WorkerThread() override;

      // This thread attempts to get tasks in a loop from |runner_| and run them.
      void Run() override;
    private:
      DefaultWorkerThreadsTaskRunner* runner_;
    };
    // 獲取下一個task
    std::unique_ptr<Task> GetNext();

    bool terminated_ = false;
    // task隊列
    DelayedTaskQueue queue_;
    // 線程池
    std::vector<std::unique_ptr<WorkerThread>> thread_pool_;
    // 計數方法
    TimeFunction time_function_;
    std::atomic_int single_worker_thread_id_{0};
    uint32_t thread_pool_size_;
};

  這里順便把TaskRunner相關的內容也一並放出來,大部分內容可以看命名。內部類的初始化參數類型是外部類,V8完全把Thread、TaskRunner兩個類綁起來了。

 

Task

  這個只是一個簡單基類,用來繼承實現任務的。

/**
 * A Task represents a unit of work.
 */
class Task {
 public:
  virtual ~Task() = default;
  // 所有的task需要繼承這個類並實現Run方法
  virtual void Run() = 0;
};

  由於HelloWorld的sample並沒有用到多線程,所以不存在Task類的實現,這里只能先關注概念。使用時,大概方法如下,寫個偽代碼演示下。

class userTask : public Task {
  public:
    void Run() {
      // do something...
    };
};

void handleTask() {
  // 新建一個task
  auto task = new userTask();
  // 加入隊列
  queue_.push_back(task);
  // 喚醒線程
  thread_.signal();
  // 線程處理task
  while(true) {
    if(queue_.empty()) break;
    auto task = queue_pop_back();
    task->Run();
  }
  // 線程等待喚醒
  thread_.wait();
}

  過程跟其實libuv的異步操作差不多,感覺編程的套路也就那樣,看多了源碼或者有實際開發經驗的都熟悉。

  

  這一篇就先介紹一些類(調用棧和內存管理先放着),了解后基本上V8中關於Platform的內容就差不多了。關於Thread、TaskRunner、Task三者的聯系與運作,因為C++是速成的,沒去了解這些東西的實際運用,所以暫時不在這里班門弄斧了。之前學Java的時候了解過線程,感覺無論是API的名字還是概念都差不多,有興趣的可以自己去看看。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM