使用epoll驱动ucontext - phxrpc代码阅读(5)

用pipe叫醒你 — EpollNotifier

class EpollNotifier类型封装了一个使用pipe传递信号的Notifier类。

Run()函数(其实我觉得叫Register或Activate会更好)首先声明了两个单向的pipe:pipe_fds_,从文档中我们可以知道pipe_fds_[0]是读管道,而pipe_fds_[1]是写管道。这里有一丁点反直觉,就是pipe拿了两个fd,但是仍旧是单工的。

然后将读fd设为O_NONBLOCK以供epoll调度,最后将Func()函数传入scheduler_中。

这里跑个题,想起了当年我大一的时候上过的通信导论的选修课。那会我还没有沉迷代码,还是一个积极乐观好好学习的新时代大学生。自从开始写了代码,人就越来越废物了,连女朋友都找不到了。
年轻人们啊,有饭辙干点啥都行,千万别写码啊。

Func()函数做的事情很简单,就是从管道里尝试poll一段数据,拿到数据后直接扔掉。因为管道里传来的数据并没有实际意义,这样设计的主要意义在于唤醒epoll。

我们可以从Notify()函数中看出 …

more ...

ucontext - phxrpc代码阅读(4)

写在前面

国庆假期过半,phxrpc的代码阅读大概要小小告一段落啦。因为这两天还要读工作相关的代码,以及最后几天还有一次短途旅行。

所以非阻塞TCP流可能要留到下一篇了,这一篇只涉及非阻塞TCP流使用到的ucontext协程库,及其使用的一些框架代码。

161013更新:这点破东西写到今天才写完,GG。

什么是ucontext

"Subroutines are special cases of ... coroutines." –Donald Knuth.

首先我们来看一下,什么是线程。线程是进程内一条执行流的状态,包含了硬件状态(硬件计数器,寄存器,条件码等)和堆栈中的数据。

线程通常只有一个入口和一个出口。当线程返回时,线程的生命周期也结束了。所以,通常线程的执行由内核调度。

协程的定义与线程类似,也是硬件状态+堆栈的状态组合。但是与线程不同的是,协程可以有多个出口。可以通过yield来暂停自己,调用其它协程。再次启动时,会从上次挂起的地方继续运行。

phxrpc中的ucontext

phxrpc提供了system和boost两种ucontext的实现,所以提供了一个uthread_context_base的基类。其实在这里我是有一点怀疑虚函数的性能的,不过好在协程的切换以及网络IO操作还是比较耗性能的,所以虚函数多出来的几次内存寻址也并非不能接受 …

more ...