GRPC-C++源碼分析(九)--Start續

2 SyncRequestThreadManager->Start

解釋第二部分代碼

<code>  //第二部分
for (auto it = sync_req_mgrs_.begin(); it != sync_req_mgrs_.end(); it++) {
(*it)->Start();
}/<code>

看下(*it)->Start()的實現

<code>  void Start() {
if (!sync_requests_.empty()) {
for (auto m = sync_requests_.begin(); m != sync_requests_.end(); m++) {
(*m)->SetupRequest();
(*m)->Request(server_->c_server(), server_cq_->cq());
}

Initialize(); // ThreadManager's Initialize()
}
}/<code>

先忽略sync_requests_部分,後邊再說,重點看Initialize()裡的實現。這裡分兩部分說,第一部分說整個框架邏輯,第二部分分析具體函數調用邏輯。

2.1 Start框架邏輯

抽象的看epoll模型的核心運轉模式。直接看圖14-1


GRPC-C++源碼分析(九)--Start續

14-1


  • 注意下藍色框內容,grpc裡的讀寫事件處理是在一個“統一的循環裡”,而這個統一的循環由grpc_core::ExecCtx::Get()->Flush()來控制
  • 圖14-2演示了Flush是如何調度任務的


GRPC-C++源碼分析(九)--Start續

14-2


  • 1、2箭頭過後,已經把readable或者writable的任務放入了closure_list中
  • 3箭頭開始for循環執行Flush操作,Flush會執行closure_list的任務,當closure_list為空後,會執行combiner_data中的任務
  • 第一種場景:執行closure_list中的job1,又生成了新的job1-1放入了closure_list中,見路徑:4-4.1-4.2-4.3
  • 第二種場景:執行closure_list中的job1,又生成了新的job1-1放入了combiner_data中,見路徑:4-4.1-4.4-4.5
  • 第三中場景:執行combiner_data中的job2,又生成了新的job2-1放入了combiner_data中,見路徑:5-5.1-5.2-5.3
  • 第四種場景:執行combiner_data中的job2,又生成了新的job2-1放入了closure_list中,見路徑:5-5.1-5.4-5.5

2.2 具體函數邏輯

2.2.1 PollForWork

先看PollForWork部分邏輯,PollForWork在for循環中epoll_wait等待client鏈接

下面先介紹accept描述符的建立和註冊

GRPC-C++源碼分析(九)--Start續

15-1


  • 當前在epoll中註冊的是listen描述符,當有請求鏈接時,會觸發fd_become_readable,繼而調用on_read方法
  • 在十三章的1.1-4圖中已經介紹了on_read方法是怎樣被調用的,紅框的grpc_fd_notify_on_read已經提前設置了該方法
  • 箭頭2:藍色框中的代碼描述了把accept描述放到不同的pollsets中,也就是放到不同的epoll模型中
  • 箭頭3:創建了新的epollfd,並把listenfd和acceptfd都註冊到了新的epollfd中
  • 箭頭5:前面已經建立了accept描述符,後續會調用on_accept為接受數據做準備注意,在grpc_tcp_create中,有個vtable和tcp_handle_read會在後面用到,看代碼時候不要忽略掉

繼續看下箭頭5on_accept函數的流程


GRPC-C++源碼分析(九)--Start續

15-2


  • 把pollset放到了pollset_set中

繼續看箭頭3 on_handshake_done流程


GRPC-C++源碼分析(九)--Start續

15-3


  • 15-3圖只是一個簡圖,其中很多細節邏輯並沒有標出來。只是為了說明主流程
  • 注意藍色的箭頭,分別是write_action_begin_locked任務進入combiner_data裡,read_action_locked任務進入clousre_list裡,這樣在後面grpc_core::ExecCtx::Get()->Flush()時候,就會執行到它們
  • 可以對照第十四章的14-2圖進行理解

當上面的accept工作完成後,epoll會繼續等待具體請求內容的到來並處理,這一部分的工作模式與上面是一樣的,由於個人精力問題,沒有再去詳細整理,歡迎小夥伴補充。抓住兩個核心:tcp_send(tcp_posix.cc)、tcp_do_read(tcp_posix.cc),它們別分負責寫和讀

後面剩下的一點內容是DoWork,將在下面說明


2.2.2 DoWork

DoWork用來處理程序一開始時候註冊的service邏輯

GRPC-C++源碼分析(九)--Start續

16-1


  • DoWork的邏輯集中在CallData的Run函數中
  • 處理完SayHello函數後,可以看到最後調用了tcp_send,發送了結果
  • 16-1圖中的MethodHandler來自第十章Register,見圖16-2的右上角
GRPC-C++源碼分析(九)--Start續

16-2


GRPC C++部分的源碼分析暫時寫到這裡,後面的分析比較粗糙,我自己也覺得不滿意,但限於時間,只能先到這兒了。等閒下來時候或許會把缺失的細節補上。同時也非常歡迎有感興趣的同學前來補充。


分享到:


相關文章: