2014-09-03
--
==libev學習筆記 ==
參考:
1. http://pod.tst.eu/http://cvs.schmorp.de/libev/ev.pod
2.
簡介:
libev - a high performance full-featured event loop written in C
libev是Marc Lehmann用C寫的高效能事件迴圈庫。通過libev,可以靈活地把各種事件組織管理起來,如:時鐘、io、訊號等。libev在業界內也是廣受好評,不少項目都採用它來做底層的事件迴圈。
libev所實現的功能就是一個強大的reactor,可以notify的事件主要包括下面這些:
ev_io // IO可讀可寫
ev_stat // 檔案屬性變化
ev_signal // 訊號處理
ev_timer // 相對定時器
ev_periodic // 絕對定時器
ev_child // 子進程狀態變化
ev_fork // fork事件
ev_cleanup // event loop退出觸發事件
ev_idle // event loop空閑觸發事件
ev_embed // 嵌入另一個後台迴圈
ev_prepare // event loop之前事件
ev_check // event loop之後事件
ev_async // 線程間非同步事件
1. 一些宏定義:
/* support multiple event loops */
#if EV_MULTIPLICITY
struct ev_loop;
# define EV_P struct ev_loop *loop /* a loop as sole parameter in a declaration */
# define EV_P_ EV_P, /* a loop as first of multiple parameters */
# define EV_A loop /* a loop as sole argument to a function call */
# define EV_A_ EV_A, /* a loop as first of multiple arguments */
ev_loop是主迴圈,而EV_MULTIPLICITY是一個條件編譯的宏,表明是否支援有多個ev_loop執行個體存在,一般來說,每個線程中有且僅有一個ev_loop執行個體。
如果整個程式是單線程的,程式中使用全域預設的ev_loop即可,不需要在函數中傳參。而在多線程中調 用函數很多時候都要指定函數操作的loop。
比如啟動一個io事件,調用的函數是void ev_io_start (EV_P_ ev_io *w),如果沒有定義EV_MULTIPLICITY,將會編譯成ev_io_start(io *w),
否則會編譯成ev_io_start(struct ev_loop *loop, ev_io *w)。 對於每一種事件,都有結構體ev_TYPE與之對應,比如ev_io,ev_timer等。
為了統一事件結構,libev在C中使用結構體布局實現了多態,可以將ev_watcher結構體看做所有ev_TYPE結構體的基類,它包含了所有ev_TYPE中相同的欄位。
2. libev設定使用者自訂資料:
void ev_set_userdata (loop, void *data) /* set userdata=data */
void *ev_userdata (loop) /* return userdata */
3. ev_loop_fork(loop):
/* support multiple event loops */
while(i < PROCESS_NUM){
int pid = fork();
if(pid == 0){
ev_loop_fork(loop);
}
}
4. ev_io:
ev_io的主要使命就是監聽並響應指定檔案描述fd上的讀寫事件。對fd的監聽工作,主要委託給底層的io庫來完成。libev對目前比較流行的io庫都提供了支援,如:select, epoll以及windows的iocp等。在這裡libev使用了Adaptor模式,
通過統一的適配層隱藏了底層io庫的細節。
手冊上ev_io的介紹:
I/O watchers check whether a file descriptor is readable or writable in each iteration of the event loop, or, more precisely, when reading would not block the process and writing would at least be able to write some data. This behaviour is called level-triggering because you keep receiving events as long as the condition persists.
/* invoked when fd is either EV_READable or EV_WRITEable */
/* revent EV_READ, EV_WRITE */
typedef struct ev_io
{
EV_WATCHER_LIST (ev_io)
int fd; /* ro */
int events; /* ro */
} ev_io;
5. ev_io_init(ev, cb, fd, events):
#define ev_io_init(ev,cb,fd,events) do { ev_init ((ev), (cb)); ev_io_set ((ev),(fd),(events)); } while (0)
例如:
ev_io* read_ev_io = (ev_io*) malloc(sizeof(ev_io));
ev_io_init(read_ev_io, mysql_libev_read_callback, mysql_get_file_descriptor(mysql), EV_READ);
6. ev_io_start(loop, ev):
接上例:
ev_io_start(loop, read_ev_io)
7. ev_io_stop(loop, ev):
接上例:
ev_io_stop(loop, read_ev_io)