libevent中,有三種事件,分別爲IO(READ,WRITE),SIGNAL,TIMEOUT,對應於struct base中的三個鏈表和一個堆,其中ev_next用於串聯全部(IO, SIGNAL) event,ev_active_next用於串聯活動的事件(不一樣的優先級對應於多個活動事件鏈表),ev_signal_next用於串聯信號事件(每一個信號對應一個信號事件鏈表),min_heap_idx用於指向TIMEOUT事件在最小堆中的位置:
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 */
event不能單獨的存在,而是被event_base結構組織在一塊兒。在event_base中,struct event_list **activequenes用於組織不一樣優先級的活動事件,struct min_heap timeheap用於組織全部TIMEOUT事件,struct evsignal_info sig用於組織全部的SIGNAL事件。而struct event_list eventquene用於組織全部被插入的事件(包括IO,SIGNAL,不包含TIMEOUT)。
調用event_add添加事件時,若是是TIMEOUT事件,則添加到最小堆中;不然(IO,SIGNAL)先調用對應實現相關的add函數進行註冊,而後調用event_queue_insert,將事件添加到eventquene中。
event_queue_insert函數根據插入類型quene選擇不一樣的鏈表進行插入。
代碼以下:
int event_add(struct event *ev, const struct timeval *tv)
{
if (tv != NULL && !(ev->ev_flags & EVLIST_TIMEOUT)) {
if (min_heap_reserve(&base->timeheap,
1 + min_heap_size(&base->timeheap)) == -1)
return (-1); /* ENOMEM == errno */
}
if ((ev->ev_events & (EV_READ|EV_WRITE|EV_SIGNAL)) &&
!(ev->ev_flags & (EVLIST_INSERTED|EVLIST_ACTIVE))) {
res = evsel->add(evbase, ev);
/*調用select_add或者 epoll_add,他們根據事件是否爲signal決定是否調用evsignal_add*/
if (res != -1)
event_queue_insert(base, ev, EVLIST_INSERTED);
/* 插入到事件列表 */
}
}
void event_queue_insert(struct event_base *base, struct event *ev, int queue)
{ //略過部分
switch (queue) {
case EVLIST_INSERTED:
TAILQ_INSERT_TAIL(&base->eventqueue, ev, ev_next);
break;
case EVLIST_ACTIVE:
base->event_count_active++;
TAILQ_INSERT_TAIL(base->activequeues[ev->ev_pri],
ev,ev_active_next);
break;
case EVLIST_TIMEOUT: {
min_heap_push(&base->timeheap, ev);
break;
}
}
SIGNAL事件:
全局變量 struct event_base *evsignal_base = NULL;
int evsignal_add(struct event *ev)
{
int evsignal;
struct event_base *base = ev->ev_base;
struct evsignal_info *sig = &ev->ev_base->sig;
evsignal = EVENT_SIGNAL(ev);
if (TAILQ_EMPTY(&sig->evsigevents[evsignal])) {
if (_evsignal_set_handler(
base, evsignal, evsignal_handler) == -1)
return (-1);
/* catch signals if they happen quickly */
evsignal_base = base;
/*
第一次添加信號時將ev_signal_added置爲1,這樣在主循環中就能夠處理信號了。
不然當ev_signal_added爲0時,不會處理信號
第一次添加信號事件時,該事件被調用了2次event_add,可是第二次調用的時候,
!(ev->ev_flags & (EVLIST_INSERTED|EVLIST_ACTIVE) 判斷失敗,
所以不會進行實際的插入操做
*/
if (!sig->ev_signal_added) {
if (event_add(&sig->ev_signal, NULL))
return (-1);
sig->ev_signal_added = 1;
}
}
/* multiple events may listen to the same signal */
TAILQ_INSERT_TAIL(&sig->evsigevents[evsignal], ev, ev_signal_next);
/*插入到對應的事件列表*/
return (0);
}
static void evsignal_handler(int sig)
{
evsignal_base->sig.evsigcaught[sig]++;
/* 將計數器加1 */
evsignal_base->sig.evsignal_caught = 1;
#ifndef HAVE_SIGACTION
signal(sig, evsignal_handler);
#endif
/* Wake up our notification mechanism */
send(evsignal_base->sig.ev_signal_pair[0], "a", 1, 0);
/*寫入一個字節到socket,用於喚醒調用者來處理信號,see:evsignal_init*/
}
/* 用於在xx_dispatch中處理信號 */
void evsignal_process(struct event_base *base)
{
struct evsignal_info *sig = &base->sig;
struct event *ev, *next_ev;
sig_atomic_t ncalls;
int i;
base->sig.evsignal_caught = 0;
for (i = 1; i < NSIG; ++i) {
ncalls = sig->evsigcaught[i];
if (ncalls == 0)
continue;
for (ev = TAILQ_FIRST(&sig->evsigevents[i]);
ev != NULL; ev = next_ev) {
next_ev = TAILQ_NEXT(ev, ev_signal_next);
if (!(ev->ev_events & EV_PERSIST))
event_del(ev);
event_active(ev, EV_SIGNAL, ncalls);
/*將信號事件加入活動隊列*/ } sig->evsigcaught[i] = 0; } }