libev笔记
libev是一个开源库,实现了一个reactor模式事件驱动任务调度库。代码非常精简,包含所有实现的.c文件只有不到5000行。
支持的事件类型:
ev_io
ev_timer
ev_periodic
ev_signal
ev_child
ev_stat
ev_idle
ev_prepare and ev_check
ev_embed
ev_fork
ev_cleanup
ev_async
常用的事件类型:
ev_io,io就绪事件
ev_timer,定时器事件
ev_signal,信号事件
官方使用例子
ev_io
static void stdin_readable_cb (struct ev_loop *loop, ev_io *w, int revents) { ev_io_stop (loop, w); .. read from stdin here (or from w->fd) and handle any I/O errors } ... struct ev_loop *loop = ev_default_init (0); ev_io stdin_readable; ev_io_init (&stdin_readable, stdin_readable_cb, STDIN_FILENO, EV_READ); ev_io_start (loop, &stdin_readable); ev_run (loop, 0);ev_timer
static void one_minute_cb (struct ev_loop *loop, ev_timer *w, int revents) { .. one minute over, w is actually stopped right here } ev_timer mytimer; ev_timer_init (&mytimer, one_minute_cb, 60., 0.); ev_timer_start (loop, &mytimer);
static void timeout_cb (struct ev_loop *loop, ev_timer *w, int revents) { .. ten seconds without any activity } ev_timer mytimer; ev_timer_init (&mytimer, timeout_cb, 0., 10.); /* note, only repeat used */ ev_timer_again (&mytimer); /* start timer */ ev_run (loop, 0); // and in some piece of code that gets executed on any "activity": // reset the timeout to start ticking again at 10 seconds ev_timer_again (&mytimer);ev_signal
static void sigint_cb (struct ev_loop *loop, ev_signal *w, int revents) { ev_break (loop, EVBREAK_ALL); } ev_signal signal_watcher; ev_signal_init (&signal_watcher, sigint_cb, SIGINT); ev_signal_start (loop, &signal_watcher);关键代码分析
ev.h
核心h文件
typedef struct ev_watcher
{
EV_WATCHER (ev_watcher)
} ev_watcher;
/* shared by all watchers */
#define EV_WATCHER(type) \
int active; /* private */ \
int pending; /* private */ \
EV_DECL_PRIORITY /* private */ \
EV_COMMON /* rw */ \
EV_CB_DECLARE (type) /* private */
libev中的基础数据类型是ev_watcher,所有的事件都可以通过(W)watcher转换成ev_watcher,ev_watcher提供通用的抽象接口ev_start、ev_stop
ev_watcher是一种c方式实现的继承、多态、封装,ev_start和ev_stop就是基类ev_watcher提供的抽象接口
ev_io/ev_timer/ev_async都继承自ev_watcher
ev.c
核心c代码
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
};
reactor的核心结构体,因为成员变量众多,把详细的定义包含在ev_vars.h中。
ev_vars.h
io事件处理器列表,文件描述符fd作为数组下标
fd关注的事件发生后,查找anfds[fd]的事件处理器,检查触发事件并调用fd所有关联的处理函数。
ANFD * anfds;
ANFD的定义在ev.c中
/*保存fd事件信息的结构*/
//loop初始化的时候会初始化一个ANFD数组,每个ANFD表示一个fd对应的这个fd的所有事件信息
typedef struct
{
//每个fd可以有多个事件
WL head;
unsigned char events; /* 事件的类型 */
unsigned char reify; /* (EV_ANFD_REIFY, EV__IOFDSET) */
unsigned char emask; /* epoll后端的实际内核mask */
unsigned char unused;
//不同多路复用API的专用变量
//epoll
#if EV_USE_EPOLL
unsigned int egen; /* generation counter to counter epoll bugs */
#endif
//windows平台
#if EV_SELECT_IS_WINSOCKET || EV_USE_IOCP
SOCKET handle;
#endif
#if EV_USE_IOCP
OVERLAPPED or, ow;
#endif
} ANFD;
ev_io的观察列表,ev_io_start把事件处理器注册到ev_loop的fdchanges列表。
int* fdchanges;
ev_wrap.h
包装器头文件,简化了代码量,也增加了代码的阅读难度
抽几个关键的宏贴出来
#define fdchanges ((loop)->fdchanges)
#define anfds ((loop)->anfds)
这些宏是有益还是有害,仁者见仁智者见智
事件主循环
int ev_run(ev_loop *loop, int flags)
{
//检查关注fd列表fdchanges,新增加或者修改的fd都保存在这个列表中
//通过fd查找注册的事件处理器ANFD,检查事件处理器的关注事件
fd_reify
调用跨平台的多路复用api,封装过的,epoll的封装在ev_epoll.c
backend_poll
把事件加入待处理列表
ev_feed_event
//调用所有的待处理事件处理器
ev_invoke_pending
}