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的定義在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
}