Libev源码解析

来源:互联网 发布:如何评价中国股市知乎 编辑:程序博客网 时间:2024/06/06 00:58

最近在看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.podlibev官方文档)
http://blog.chinaunix.net/uid-8048969-id-5008922.html(事件库libev)



0 0
原创粉丝点击