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这几个自定义的宏,分别表示协程的准备,结束,协程调度器以及协程的创建。

# PhxRPC

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×