最近在看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_timetypedef 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_timertypedef 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_iotypedef 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;
ANPENDINGtypedef struct {
ev_watcher* w;
int events;
} ANPENDING;
堆結構的節點(用於管理定時器)typedef struct {
ev_tstamp at;
ev_watcher_time* w;
} ANHE;
開始前準備:
ev_init(ev_TYPE *watcher, callback)
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執行流程
通過epoll_poll之後,已經將就緒的IO事件放入pendings數組中,隨後需要放入的是最小堆中的超時watcher。超時watcher放入過程如下:
在處理最小堆的watcher時,會先講watcher放入rfeeds數組中,隨後再逆序從rfeed中事件放入pendings數組中。這兩個數組的關係如下:
在收集完所有的watcher之後,進入EV_INVOKE_PENDING的流程中,也就是從pendings數組中按照優先級順序從數組中逆序去除watcher進行invoke_cb的回調。
具體過程如下:
其中pending數組和EV_INVOKE_PEINDING的過程關係圖如下: