PhxRPC源碼分析(二)uthread_context

uthread

協程的概念在coroutine源碼分析中有介紹。phxrpc默認使用ucontext作實現,同時還有boost優化版本。

UThreadContext

UThreadContext是定義了協程接口的基類,並且有一個靜態函數對象,用來創建協程上下文,其應該是子類的DoCreate函數,

UThreaStackMemory

UThreaStackMemory是每個協程的私有棧,這裏並沒有實現共享棧模式,節省了拷貝,而且內存分配也沒有使用malloc,而是使用的mmap,這裏設置了一個標誌變量need_protect_來選擇是否開啓保護模式,開啓保護模式會在棧兩端各多分配一頁,並將這兩頁設置PROT_NONE屬性禁止訪問。調用mmap時同時設置了MAP_ANONYMOUS | MAP_PRIVATE,MAP_ANONYMOUS表示這段內存是匿名的,不需要讀寫fd。MAP_PRIVATE建立一個私有映射,不與其他進程共享。

UThreadContextSystem

UThreadContextSystem是默認的使用ucontext作實現的協程上下文。每個上下文維護一個context_表示協程的上下文,同時還有一個static __thread修飾的main_context_,表示每個線程只有一個,協程yield的時候會切換到這個上下文。
Resume函數切換到一個協程,Yield函數切出當前協程。
UThreadFuncWrapper包裝了協程的執行函數,協程運行時會切換到這個函數,函數的參數就是this指針,之後調用綁定的執行函數UThreadFunc_t和回調函數UThreadDoneCallback_t
這裏之所以將指針拆成兩個32位是因爲setcontext接受的是int類型的參數。

UThreadRuntime

UThreadRuntime封裝了協程的調度,context_list_保存所有協程上下文,這裏把每個上下文封裝成一個ContextSlot,其中的next_done_item保存下一個可用的slot下標。
first_done_item_可以看做始終保存一個已經完成的上下文的下標。Create函數創建一個上下文,首先檢查first_done_item_是否大於0 ,如果是說明此時有執行完的協程,更新first_done_item_的值然後直接更換此協程的上下文。UThreadDoneCallback回調將當前first_done_item_保存到next_done_item,然後將其更新爲自身。這樣實現了上下文的複用。
YieldResume封裝了UThreadContext對應的操作。

UThreadEpollScheduler

UThreadEpollScheduler封裝了epoll驅動的協程調度,UThreadSocket_t封裝了socket及其他相關資源。
我們主要分析一下RunForever函數的執行過程。
RunForever首先會調用EpollNotifierRun函數,Run函數會將其Func函數加入調度器的任務隊列,Func函數會去讀管道,這樣做是爲了喚醒epoll。
接下來調用ConsumeTodoList函數,會將任務隊列中的函數創建爲協程,並Resume切換到協程,協程中會將fd相應的操作在epoll中註冊然後Yield回到Run。之後Run函數調用epoll_wait檢查活動的fd,並Resume到活動fd的協程進行IO操作。這樣實現了異步操作。
處理完活動的事件後,還會不斷調用active_socket_func_()繼續Resume
最後執行新建連接的回調並處理超時事件。
主要的執行流程如下:
這裏寫圖片描述

UTreadPoll

UTreadPoll有兩個版本,分別poll一個和一組socket,主要功能就是epoll_ctl註冊對應事件後YieldResume回來後刪除註冊。

當poll一組socket時的實現比較特殊,首先epoll_create一個新的epollfd,將所有的socket註冊到新的epollfd中,然後新建一個UThreadSocket_t將其中的socketfd設爲剛纔新建的epollfd,並註冊到調度器的epoll中,這樣新建的epoll有活動事件時會觸發調度器的epoll Resume回來,注意此時對新建的epollfd執行epoll_wait的超時參數設爲0,因爲一定有活動的事件。
UThreadAcceptUThreadRead等函數都是利用UThreadPoll改造的IO函數,比較簡單。

__uthread

__uthread重載了-操作符,來實現使用uthread_t將協程加入調度器任務隊列。

uthread_begin, uthread_end, uthread_s, uthread_t這幾個自定義的宏,分別表示協程的準備,結束,協程調度器以及協程的創建。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章