1 libevent的核心-event
Libevent是基於事件驅動(event-driven)的,從名字也可以看到event是整個庫的核心。event就是Reactor框架中的事件處理程序組件;它提供了函數接口,供Reactor在事件發生時調用,以執行相應的事件處理,通常它會綁定一個有效的句柄。
首先給出event結構體的聲明,它位於event.h文件中:
- struct event {
- TAILQ_ENTRY (event) ev_next;
- TAILQ_ENTRY (event) ev_active_next;
- TAILQ_ENTRY (event) ev_signal_next;
- unsigned int min_heap_idx; /* for managing timeouts */
- struct event_base *ev_base;
- int ev_fd;
- short ev_events;
- short ev_ncalls;
- short *ev_pncalls; /* Allows deletes in callback */
- struct timeval ev_timeout;
- int ev_pri; /* smaller numbers are higher priority */
- void (*ev_callback)(int, short, void *arg);
- void *ev_arg;
- int ev_res; /* result passed to event callback */
- int ev_flags;
- };
下面簡單解釋一下結構體中各字段的含義。
1)ev_events:event關注的事件類型,它可以是以下3種類型:
I/O事件: EV_WRITE和EV_READ
定時事件:EV_TIMEOUT
信號: EV_SIGNAL
輔助選項:EV_PERSIST,表明是一個永久事件
Libevent中的定義爲:
- #define EV_TIMEOUT 0x01
- #define EV_READ 0x02
- #define EV_WRITE 0x04
- #define EV_SIGNAL 0x08
- #define EV_PERSIST 0x10 /* Persistant event */
可以看出事件類型可以使用“|”運算符進行組合,需要說明的是,信號和I/O事件不能同時設置;
還可以看出libevent使用event結構體將這3種事件的處理統一起來;
2)ev_next,ev_active_next和ev_signal_next都是雙向鏈表節點指針;它們是libevent對不同事件類型和在不同的時期,對事件的管理時使用到的字段。
libevent使用雙向鏈表保存所有註冊的I/O和Signal事件,ev_next就是該I/O事件在鏈表中的位置;稱此鏈表爲“已註冊事件鏈表”;
同樣ev_signal_next就是signal事件在signal事件鏈表中的位置;
ev_active_next:libevent將所有的激活事件放入到鏈表active list中,然後遍歷active list執行調度,ev_active_next就指明瞭event在active list中的位置;
2)min_heap_idx和ev_timeout,如果是timeout事件,它們是event在小根堆中的索引和超時值,libevent使用小根堆來管理定時事件,這將在後面定時事件處理時專門講解
3)ev_base該事件所屬的反應堆實例,這是一個event_base結構體,下一節將會詳細講解;
4)ev_fd,對於I/O事件,是綁定的文件描述符;對於signal事件,是綁定的信號;
5)ev_callback,event的回調函數,被ev_base調用,執行事件處理程序,這是一個函數指針,原型爲:
void (*ev_callback)(int fd, short events, void *arg)
其中參數fd對應於ev_fd;events對應於ev_events;arg對應於ev_arg;
6)ev_arg:void*,表明可以是任意類型的數據,在設置event時指定;
7)eb_flags:libevent用於標記event信息的字段,表明其當前的狀態,可能的值有:
- #define EVLIST_TIMEOUT 0x01 // event在time堆中
- #define EVLIST_INSERTED 0x02 // event在已註冊事件鏈表中
- #define EVLIST_SIGNAL 0x04 // 未見使用
- #define EVLIST_ACTIVE 0x08 // event在激活鏈表中
- #define EVLIST_INTERNAL 0x10 // 內部使用標記
- #define EVLIST_INIT 0x80 // event已被初始化
8)ev_ncalls:事件就緒執行時,調用ev_callback的次數,通常爲1;
9)ev_pncalls:指針,通常指向ev_ncalls或者爲NULL;
10)ev_res:記錄了當前激活事件的類型;
2 libevent對event的管理
從event結構體中的3個鏈表節點指針和一個堆索引出發,大體上也能窺出libevent對event的管理方法了,可以參見下面的示意圖:
每次當有事件event轉變爲就緒狀態時,libevent就會把它移入到active event list[priority]中,其中priority是event的優先級;
接着libevent會根據自己的調度策略選擇就緒事件,調用其cb_callback()函數執行事件處理;並根據就緒的句柄和事件類型填充cb_callback函數的參數。
3 事件設置的接口函數
要向libevent添加一個事件,需要首先設置event對象,這通過調用libevent提供的函數有:event_set(), event_base_set(), event_priority_set()來完成;下面分別進行講解。
void event_set(struct event *ev, int fd, short events,
void (*callback)(int, short, void *), void *arg)
1.設置事件ev綁定的文件描述符或者信號,對於定時事件,設爲-1即可;
2.設置事件類型,比如EV_READ|EV_PERSIST, EV_WRITE, EV_SIGNAL等;
3.設置事件的回調函數以及參數arg;
4.初始化其它字段,比如缺省的event_base和優先級;
int event_base_set(struct event_base *base, struct event *ev)
設置event ev將要註冊到的event_base;
libevent有一個全局event_base指針current_base,默認情況下事件ev將被註冊到current_base上,使用該函數可以指定不同的event_base;
如果一個進程中存在多個libevent實例,則必須要調用該函數爲event設置不同的event_base;
int event_priority_set(struct event *ev, int pri)
設置event ev的優先級,沒什麼可說的,注意的一點就是:當ev正處於就緒狀態時,不能設置,返回-1。
4 小結
本節講述了libevent的核心event結構,以及libevent支持的事件類型和libevent對event的管理模型;接下來將會描述libevent的事件處理框架,以及其中使用的重要的結構體event_base;