GRPC-C++源碼分析(八)--Start

對應《GRPC-C++源碼分析(三)--main函數主要流程》中1.6節

這一節可能才是最核心的部分,包括大家理解的怎樣註冊listen和accept描述符,怎樣處理讀寫事件,怎樣處理業務邏輯等等。

由於這部分涉及的方面太多了,筆者也只是梳理出了核心的部分供參考,歡迎有精力的小夥伴繼續補充。

<code>server->Start(cqs_data, cqs_.size());/<code>

在Server::Start的實現中,主要分兩部分

<code>//第一部分
grpc_server_start(server_);/<code>
  • 建立epoll,listen描述符註冊
<code>  //第二部分
for (auto it = sync_req_mgrs_.begin(); it != sync_req_mgrs_.end(); it++) {
(*it)->Start();
}/<code>
  • accept描述符註冊,讀寫事件響應,處理註冊的service業務邏輯

下面對這兩部分分別進行解釋

1 grpc_server_start

在grpc_server_start函數中也分兩部分說明:

<code>//第一部分
for (i = 0; i < server->cq_count; i++) {

if (grpc_cq_can_listen(server->cqs[i])) {
server->pollsets[server->pollset_count++] =
grpc_cq_pollset(server->cqs[i]);
}
}/<code>
  • 重點理解server->pollsets[server->pollset_count++]=grpc_cq_pollset(server->cqs[i]);看下圖


GRPC-C++源碼分析(八)--Start

  • 一句話,把cqs中的grpc_pollset指針放到grpc_server的指針數組pollsets中
<code>//第二部分
GRPC_CLOSURE_SCHED(
GRPC_CLOSURE_CREATE(
start_listeners, server,
grpc_core::Executor::Scheduler(grpc_core::ExecutorJobType::SHORT)),
GRPC_ERROR_NONE);/<code>
  • 這塊代碼對應了《GRPC-C++源碼分析(一)--網絡模型》中將start_listeners放入default-excutor線程中執行
  • 跟蹤下grpc_core::Executor::Scheduler可以清晰看到最終調用的是grpc_closure_list_append方法


GRPC-C++源碼分析(八)--Start

  • 《GRPC-C++源碼分析(七)--bind&listen》中的server_start_listener在這裡被調用了
  • 下面繼續看server_start_listener方法

1.1 server_start_listener

這個函數完成了epoll的創建,listen描述符的註冊


GRPC-C++源碼分析(八)--Start

1.1-1

  • server_start_listener最終調用的是tcp_server_start
  • 分段解釋下tcp_server_start
<code>//tcp_server_posix.cc
static void tcp_server_start(grpc_tcp_server* s, grpc_pollset** pollsets,
size_t pollset_count,
grpc_tcp_server_cb on_accept_cb,
void* on_accept_cb_arg) {
size_t i;
grpc_tcp_listener* sp;
GPR_ASSERT(on_accept_cb);
gpr_mu_lock(&s->mu);
GPR_ASSERT(!s->on_accept_cb);
GPR_ASSERT(s->active_ports == 0);
s->on_accept_cb = on_accept_cb;
s->on_accept_cb_arg = on_accept_cb_arg;
s->pollsets = pollsets;
s->pollset_count = pollset_count;
sp = s->head;/<code>


GRPC-C++源碼分析(八)--Start

1.1-2

  • 上圖沒有複雜東西,畫出來幫助理解賦值關係而已
  • 注意右邊的active_pollable,後面繼續調用的grpc_pollset_add_fd方法,把創建epoll的描述符epfd放到了這裡
<code>      for (i = 0; i < pollset_count; i++) {
grpc_pollset_add_fd(pollsets[i], sp->emfd);
}/<code>


GRPC-C++源碼分析(八)--Start

1.1-3

  • epoll的創建,描述符的註冊見上圖的藍色框
  • epoll的描述符epfd保存在了1.1-2圖裡的pollable裡
<code>      GRPC_CLOSURE_INIT(&sp->read_closure, on_read, sp,
grpc_schedule_on_exec_ctx);
grpc_fd_notify_on_read(sp->emfd, &sp->read_closure);/<code>
  • GRPC_CLOSURE_INIT簡單的理解為將on_read方法綁定在sp->read_closure中即可
  • grpc_fd_notify_on_read的實現見1.1-4
GRPC-C++源碼分析(八)--Start

1.1-4

  • grpc_fd_notify_on_read設置完的東西,在1.1-4圖中粉色虛線框裡的fd_become_readable方法中使用
  • 大體意思是將on_read方法綁定在sp->read_closure,然後將sp->read_closure再綁定在sp->emfd->read_closure裡。這些綁定會在後面的fd_become_readable中用到


分享到:


相關文章: