HHVM源碼剖析

1、前言

hhvm源碼中充滿了不少C++11的新特性,而且使用了各類設計模式如工廠,模板方法等,利用智能指針包裹指針,讓delete沒有肆意的出現設計模式

模板,繼承,explicit,純虛函數的出現令代碼中充滿了驚喜網絡

例以下面這段代碼:run_函數是pthread_create執行的函數async

 NewImage

 

2、hhvm啓動流程總覽

hhvm/main.cpp函數

NewImage

75行:調用execute_program函數進行具體的邏輯oop

 

runtime/base/program-functions.cpp 源碼分析

NewImage

885行:調用execute_program_impl進行具體的邏輯post

 

runtime/base/program-functions.cpp spa

NewImage

1260:  從配置文件中加載配置項線程

1475:函數負責啓動線程與接收處理請求設計

 

整體流程圖以下:

 

NewImage

 

RuntimeOption::Load函數負責加載配置文件中的配置項

start_server函數負責啓動線程與接收處理請求

 

3、Load函數配置文件的加載與處理

 

以以下配置項的解析爲例

Server{
Type= FastCGIServer
ThreadCount=20
###......
}

 

runtime/base/runtime-option.cpp

NewImage

782-801行 解析配置文件中Server塊中的內容

787行 將配置文件中的type值FastCGIServer賦值給ServerType

800行 將配置文件中的ThreadCount賦值給ServerThreadCount

因此ServerType的值爲FastCGIServer

ServerThreadCount的值爲20

4、start_server初始化HttpServer對象

runtime/base/program-functions.cpp 

NewImage

799行  初始化HttpServer對象

837行 啓動server,接受處理請求

httpserver對象的初始化函數

 

runtime/server/http-server.cpp 

NewImage

88行 KNumProcessors爲系統內核的個數,經過62行的 const int kNumProcessors = sysconf(_SC_NPROCESSORS_ONLN);得到

84-90行:若是配置的thread大於系統的內核的個數,則在啓動時只啓動與系統內核個數相同的thread數,將其他的個數賦值給additionalThreads

92行:調用工廠函數,針對ServerType:FastCGIServerc生成一個工廠對象

96-101行:將配置文件中的信息賦值給options對象,注意這裏的startingThreadCount最大爲系統內核的個數

102行:根據options配置信息生成一個Server

 

 

runtime/server/fastcgi/fastcgi-server-factory.cpp 

NewImage

聽過FastCGIServerFactory工廠生成一個FastCGIServer對象

 

FastCGIServer的構造函數

runtime/server/fastcgi/fastcgi-server.cpp  

NewImage

這裏的worker就是啓動的線程數目

 

這裏關注一下m_dispatcher的初始化

 

runtime/server/fastcgi/fastcgi-server.h 

JobQueueDispatcher<FastCGIWorker> m_dispatcher;   

m_dispatcher的類型爲JobQueueDispatcher

 

FastCGIWorker的定義以下:

typedef ServerWorker<std::shared_ptr<FastCGIJob>,FastCGITransportTraits> FastCGIWorker;

 

struct ServerWorker  : JobQueueWorker<JobPtr,Server*,true,false,JobQueueDropVMStack>{}//傳入的第三個參數爲true

template<typename TJob, typename TContext = void*, bool countActive = false, bool waitable = false, class Policy = detail::NoDropCachePolicy> 
class JobQueueWorker {}

ServerWorker的繼承關係以下

NewImage

因此這裏的countActive爲true

NewImage

467-473行:因爲CountActivewe== true因此不會進入下方的邏輯中

util/job-queue.h

NewImage

656-658行 一樣因爲CountActive== true 所以不會走入656-658行裏面

 

 

5、start_server RunOrExitProcess啓動一個Server

runtime/server/http-server.cpp 

NewImage 

262-268行 因爲沒有配置 ThreadDocuments,ThreadLoopDocuments因此size()大小爲0 不會走入

269行 ServerPort的初始化值爲80,只要配置文件中的Port值不爲0(即便配置文件中沒有Server.Port值,也會初始化爲80) 就會走入

runtime/base/runtime-option.cpp

121 int RuntimeOption::ServerPort = 80; 

相比之下

AdminServer.Port的值初始化爲0

runtime/base/runtime-option.cpp

266 int RuntimeOption::AdminServerPort = 0; 

所以只有配置了纔會啓動AdminServer

 

runtime/server/http-server.cpp

NewImage

非AdminServer的時候 傳入的pageServer==true由於走入579行

這裏的m_pageServer爲fastcgi-server對象

 

 

runtime/server/fastcgi/fastcgi-server.cpp 

NewImage

263行 m_worker.start()經過C++11的thread啓動一個線程負責網絡IO

264行 m_dispatcher.start() 經過pthread_create啓動若干線程負責CPU部分

 

下面看一看m_dispatcher.start的詳細邏輯

util/job-queue.h  

NewImage

513-516行 若是配置的threadCount太小的話 這裏會進行增長

517-520行 經過start()函數建立線程

 

util/job-queue.h 

NewImage

 

util/async-func.h 

NewImage

AsyncFunc繼承自AsyncFuncImpl

AsnycFuncImpl實現了start()函數

 

NewImage

util/async-func.cpp

NewImage

至此線程啓動完畢,線程運行的函數爲ThreadFunc

 

6、ThreadFunc從何而來

ThreadFunc是從那裏來的呢?

util/async-func.cpp

NewImage

 

NewImage

 

NewImage

這裏使用了模板方法設計模式

util/async-func.h

一段神奇的代碼.....

NewImage

 

util/job-queue.h

NewImage

 

最終執行的方法以下

NewImage

NewImage

NewImage

 

 

 

個人博客即將搬運同步至騰訊雲+社區,邀請你們一同入駐:https://cloud.tencent.com/developer/support-plan

相關文章
相關標籤/搜索