前言
我們在上一個小節中分析了事件主循環的整個過程以及event_base_once
函數。可能信息量有點大,這一小節,我們把event.c
剩下的一部分重要的函數分析分析。
event_dispatch
我們再回到討論主循環這個話題來,在第1小節給的例子裏面最後調用了event_dispatch
,它其實幹的就是事件主循環的事,只是做了幾層封裝而已。
下面我們來看一看。
event_dispatch
int
event_dispatch(void)
{
return (event_loop(0));
}
裏面調用了event_loop
函數,已經和event_base_loop
很接近了。我們再往下看。
event_loop
int
event_loop(int flags)
{
return event_base_loop(current_base, flags);
}
對,event_dispatch
的實質就是調用event_base_loop(current_base, 0)
那麼這個flags到底可以取什麼值呢?我們在event_base_loop
中已經發現它可以取EVLOOP_ONCE
和EVLOOP_NONBLOCK
。
事實上,它也就只能取這兩個值,用於設置事件循環的標識。在event.h
中定義。
#define EVLOOP_ONCE 0x01 /**< Block at most once. */
#define EVLOOP_NONBLOCK 0x02 /**< Do not block. */
event_active
這個函數的作用是手動激活事件
void
event_active(struct event *ev, int res, short ncalls)
{
/* We get different kinds of events, add them together */
//當前事件已經激活了則將激活類型與之前的做或操作並返回
if (ev->ev_flags & EVLIST_ACTIVE) {
ev->ev_res |= res;
return;
}
//設置激活事件的類型以及調用次數
ev->ev_res = res;
ev->ev_ncalls = ncalls;
ev->ev_pncalls = NULL;
//插入到激活鏈表中去
event_queue_insert(ev->ev_base, ev, EVLIST_ACTIVE);
}
你可以在使用libevent的時候調用該函數來手動激活一個事件,並且可以自己指定激活事件的原因。
不過其實在監聽事件中,如果該事件滿足條件被觸發了,那麼將其添加到激活鏈表中去的函數還是event_active
。
event_process_active
前面說了這麼多,真正來調度激活事件的函數就是它了。
/*
* Active events are stored in priority queues. Lower priorities are always
* process before higher priorities. Low priority events can starve high
* priority ones.
*/
//根據libevent自帶的英文註釋來看,激活事件是按優先級來調度的,低優先級先被調度並且低優先級可能會使高優先級一直得不到調度
static void
event_process_active(struct event_base *base)
{
struct event *ev;
struct event_list *activeq = NULL;
int i;
short ncalls;
//遍歷優先級鏈表,從0開始,找到優先級最低的不爲空的激活鏈表來調度
for (i = 0; i < base->nactivequeues; ++i) {
//如果該優先級所在的鏈表不爲空,那就證明有激活事件可以調度,則跳出循環,進行處理
if (TAILQ_FIRST(base->activequeues[i]) != NULL) {
activeq = base->activequeues[i];
break;
}
}
assert(activeq != NULL);
//從該優先級的事件鏈表的頭開始調度
for (ev = TAILQ_FIRST(activeq); ev; ev = TAILQ_FIRST(activeq)) {
//如果標識位設置了是永久事件,那就只將它從激活鏈表中移出;否則將該事件註銷
if (ev->ev_events & EV_PERSIST)
event_queue_remove(base, ev, EVLIST_ACTIVE);
else
event_del(ev);
/* Allows deletes to work */
//由於之前記錄了調用次數,這裏就開始正式調用了
ncalls = ev->ev_ncalls;
ev->ev_pncalls = &ncalls;
while (ncalls) {
ncalls--;
ev->ev_ncalls = ncalls;
(*ev->ev_callback)((int)ev->ev_fd, ev->ev_res, ev->ev_arg);
if (event_gotsig || base->event_break)
return;
}
}
}
該函數的邏輯還算清晰,也不是特別長。
主要需要關注的就是activequeues
是個二級指針,不要搞忘了並且低優先級優先被調度。
最後處理的時候,如果事件類型中設置了爲EV_PERSIST
永久性事件,則激活之後只將其從激活鏈表中移出;如果沒有設置,則註銷,還記得註銷的時候幹了什麼嗎?如果記不得了,翻到第7小節再看看。
小結
在本小節我們瞭解了event.c
剩下的一些主要的函數,相信你對事件主循環更加了解了。接下來,我們就可以開始進入之前一直省略的信號以及定時部分了,看看它們是如何集成到事件主循環中的。