Libev源碼解析

最近在看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://blog.chinaunix.net/uid-8048969-id-5008922.html(事件庫libev)



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章