最近在看libev源码,算是对libev的源码有个比较清晰的了解。
总共分3部分来介绍libev.
1 Libev是什么
Libev是基于Reactor模式的一个高性能,支持高并发的事件库。它本身不仅支持IO,timer(定时器),还支持signal, fork等。并且它短小精悍 ,并且C语言实现。
2. Libev重要的数据结构
只有了解并且熟悉了Libev的基本数据结构,才能更顺利的理解Libev怎么实现的事件库的。
基类ev_watcher
typedef struct ev_watcher {
int active; // 激活标志
int pending; // 等待事件数
int priority; //优先级
void* data;
// 回调函数
void (*cb)(struct ev_loop* loop, struct ev_watcher* w, int revent);
} ev_watcher;
ev_watcher_list
typedef struct ev_watcher_list {
int active;
int pending;
int priority;
void* data;
void (*cb)(struct ev_loop* loop, struct ev_watcher_list* w, int revent);
struct ev_watcher_list* next;
} ev_watcher_list;
ev_watcher_time
typedef double ev_tstamp;
typedef struct ev_watcher_time {
int active; // 激活标志
int pending; // 等待事件数
int priority; //优先级
void* data;
// 回调函数
void (*cb)(struct ev_loop* loop, struct ev_watcher_time* w, int revent);
ev_tstamp at;
} ev_watcher_time;
ev_timer
typedef struct ev_timer {
int active; // 激活标志
int pending; // 等待事件数
int priority; //优先级
void* data;
// 回调函数
void (*cb)(struct ev_loop* loop, struct ev_watcher_time* w, int revent);
ev_tstamp at; // 在"at"之后发生timeout事件
ev_tstamp repeat; // 在"repeat"之后触发timeout事件,循环
} ev_timer;
ev_io
typedef struct ev_io {
int active;
int pending;
int priority;
void* data;
void (*cb)(struct ev_loop *loop, struct ev_io *w,int revents);
struct ev_watcher_list *next;
int fd;// 文件描述符
int events;// 事件類型
} ev_io;
typedef struct ev_signal {
int active;
int pending;
int priority;
void* data;
void (*cb)(struct ev_loop *loop, struct ev_signal *w,int revents);
struct ev_watcher_list *next;
int signum; // 信号量like SIGxxx
} ev_signal;
ev_prepare
/* invoked for each run of the mainloop, just before the blocking call */
/* you can still change events in any way you like */
/* revent EV_PREPARE */
typedef struct ev_prepare {
int active;
int pending;
int priority;
void* data;
void (*cb)(struct ev_loop *loop, struct ev_prepare *w,int revents);
} ev_prepare;
ev_check
/* invoked for each run of the mainloop, just after the blocking call */
/* revent EV_CHECK */
typedef struct ev_check {
int active;
int pending;
int priority;
void* data;
void (*cb)(struct ev_loop *loop, struct ev_check *w,int revents);
} ev_check;
ev_loop:
struct ev_loop {
ev_tstamp ev_rt_now;
#define ev_rt_now ((loop)->ev_rt_now)
#define VAR(name,decl) decl;
#include "ev_vars.h" // 包含众多成员
#undef VAR
};
ev_loop的成员:
ev_tstamp now_floor; /* last time we refreshed rt_time */
ev_tstamp mn_now; // 当前单调时间,系统开机时间
ev_tstamp rtmn_diff; // difference realtime - monotonic time
unsigned int origflags;
int backend; //epoll 、 kqueue 、 poll 、 select 、 port 标记
int activecnt;// 激活事件总数
int backend_fd;// 对于 epoll, 为 epoll_create 返回的描述符
int * fdchanges;// 事件队列
int fdchangemax;// 当前最大事件数
int fdchangecnt;// 事件数
ANPENDING *pendings [NUMPRI];// 待处理队列
int pendingmax [NUMPRI];// 当前最大等待事件的数量
int pendingcnt [NUMPRI];// 记录每个优先级的数量
ANFD:
typedef struct{
ev_watcher_list* head; //监听者链表
unsigned char events; //监听的事件
unsigned char reify;//状态位 用来表示具体是EV_ANFD_REIFY还是EV_IOFDSET
unsigned char emask;//epoll用来保存内核mask的值
unsigned char unused;//同名字
#if EV_USE_EPOLL
unsigned int egen;//
#endif
#if EV_SELECT_ISWINSOCKET || EV_USE_IOCP
SOCKET handle;//
#endif
#if EV_USE_IOCP
OVERLAPPED or,ow;//
#endif
} ANFD;
ANPENDING
typedef struct {
ev_watcher* w;
int events;
} ANPENDING;
堆结构的节点(用于管理定时器)
typedef struct {
ev_tstamp at;
ev_watcher_time* w;
} ANHE;
开始前准备:
ev_init(ev_TYPE *watcher, callback)
ev_set_priority(ev_TYPE*watcher, int priority)设置优先级
ev_io_init(ev_io *, callback, int fd, int events)
Fd: EV_READ, EV_WRITEor EV_READ | EV_WRITE
ev_io_set(ev_io *, int fd, int events)
ev_timer_init(ev_timer *, callback, ev_tstamp after, ev_tstamp repeat)
ev_timer_set(ev_timer *, ev_tstamp after, ev_tstamp repeat)
3. ev_run执行流程
下图为ev_run的具体流程:
backend_poll(epoll_poll)过程,是通过epoll_wait讲IO事件放入pendings数组里。下图为backend_poll的具体过程:
epoll_poll之后,将事件从anfds中找到对应的ANFD。
anfds, fdchanges和fd的关系如下图:
然后再取ANFD中的watcher,最后将watcher和发生的事件赋值给结构体ANPENDING,最后将ANPENDING按照优先级放入二维数组pendings中。
fd,andfs,pendings之间的关系如下:
上图表示,通过backend_poll函数中调用fd_event/fd_event_nocheck将epoll_wait之后拿到就绪fd,在用fd作为下标的anfds中查询,得到ANFD,之后通过ev_feed_event函数将watcher,event组成结构体ANPENDING,插入到pendings数组中。
通过epoll_poll之后,已经将就绪的IO事件放入pendings数组中,随后需要放入的是最小堆中的超时watcher。超时watcher放入过程如下:
在处理最小堆的watcher时,会先讲watcher放入rfeeds数组中,随后再逆序从rfeed中事件放入pendings数组中。这两个数组的关系如下:
在收集完所有的watcher之后,进入EV_INVOKE_PENDING的流程中,也就是从pendings数组中按照优先级顺序从数组中逆序去除watcher进行invoke_cb的回调。
具体过程如下:
其中pending数组和EV_INVOKE_PEINDING的过程关系图如下:
4 参考文献:
•http://pod.tst.eu/http://cvs.schmorp.de/libev/ev.pod(libev官方文档)
•http://blog.chinaunix.net/uid-8048969-id-5008922.html(事件库libev)
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)