接下來就是將已經初始化的event注冊到libevent的事件鏈表上,通過event_add()來實現,源碼位於event.c中。
event_add()
這個函數主要完成了下面幾件事:
1.將event注冊到event_base的I/O多路復用要監聽的事件中
2.將event注冊到event_base的已注冊事件鏈表中
3.如果傳入了超時時間,則刪除舊的超時時間,重新設置,並將event添加到event_base的小根堆中;
如果沒有傳入超時時間,則不會添加到小根堆中。
只有步驟1成功,才會執行步驟2和3;否則什么都沒做,直接返回,保證不會改變event的狀態。
從中還可以看到,將event添加到已注冊事件鏈表、添加到小根堆、從活躍事件鏈表移除、從小根堆中移除,都是通過兩個函數完成的:event_queue_insert()、event_queue_remove()
int event_add(struct event *ev, const struct timeval *tv) { struct event_base *base = ev->ev_base; //event所屬的event_base const struct eventop *evsel = base->evsel; //event_base的I/O多路復用機制 void *evbase = base->evbase; //event_base的I/O多路復用機制 int res = 0; //DEBUG log.h event_debug(( "event_add: event: %p, %s%s%scall %p", ev, ev->ev_events & EV_READ ? "EV_READ " : " ", ev->ev_events & EV_WRITE ? "EV_WRITE " : " ", tv ? "EV_TIMEOUT " : " ", ev->ev_callback)); assert(!(ev->ev_flags & ~EVLIST_ALL)); /* * prepare for timeout insertion further below, if we get a * failure on any step, we should not change any state. */ //如果傳入了超時時間並且event不再time小根堆上,則在小根堆上預留一個位置 //以保證如果后面有步驟失敗,不會改變初始狀態,保證是個原子操作 if (tv != NULL && !(ev->ev_flags & EVLIST_TIMEOUT)) { if (min_heap_reserve(&base->timeheap, //min_heap.h 1 + min_heap_size(&base->timeheap)) == -1) return (-1); /* ENOMEM == errno */ } //如果event不在已注冊鏈表或活躍鏈表中, //則調用evsel->add()注冊event事件到I/O多路復用監聽的事件上 if ((ev->ev_events & (EV_READ|EV_WRITE|EV_SIGNAL)) && !(ev->ev_flags & (EVLIST_INSERTED|EVLIST_ACTIVE))) { res = evsel->add(evbase, ev); //將event注冊到監聽事件上 //注冊監聽事件成功,則將event注冊到已注冊事件鏈表上 if (res != -1) event_queue_insert(base, ev, EVLIST_INSERTED); //插入 } /* * we should change the timout state only if the previous event * addition succeeded. */ //前面操作都成功情況下,才能執行下面步驟 //改變超時狀態 if (res != -1 && tv != NULL) { struct timeval now; /* * we already reserved memory above for the case where we * are not replacing an exisiting timeout. */ //EVLIST_TIMEOUT表明event已在定時器堆中 //則刪除舊的定時器 if (ev->ev_flags & EVLIST_TIMEOUT) event_queue_remove(base, ev, EVLIST_TIMEOUT); //移除 /* Check if it is active due to a timeout. Rescheduling * this timeout before the callback can be executed * removes it from the active list. */ //如果事件是由於超時而變成活躍事件 //則從活躍事件鏈表中刪除 if ((ev->ev_flags & EVLIST_ACTIVE) && (ev->ev_res & EV_TIMEOUT)) { /* See if we are just active executing this * event in a loop */ if (ev->ev_ncalls && ev->ev_pncalls) { /* Abort loop */ *ev->ev_pncalls = 0; //調用次數清0 } //從活躍事件鏈表移除 event_queue_remove(base, ev, EVLIST_ACTIVE); //移除 } gettime(base, &now); evutil_timeradd(&now, tv, &ev->ev_timeout); //為event添加超時時間 event_debug(( "event_add: timeout in %ld seconds, call %p", tv->tv_sec, ev->ev_callback)); //將event插入到小根堆中 event_queue_insert(base, ev, EVLIST_TIMEOUT); //插入 } return (res); }
event_queue_insert()
該函數根據不同的輸入隊列,即不同的事件,在不同的隊列中插入,並增加相應的事件計數,更新event狀態;
EVLIST_INSERTED:在已注冊事件鏈表event_base.eventqueue插入
EVLIST_ACTIVE:根據event優先級,在活躍事件鏈表event_base.activequeues[event.ev_pri]插入
EVLIST_TIMEOUT:在小根堆event_base.timeheap中插入
void event_queue_insert(struct event_base *base, struct event *ev, int queue) { //如果event已經在活躍鏈表中,則返回;否則,出錯 if (ev->ev_flags & queue) { /* Double insertion is possible for active events */ if (queue & EVLIST_ACTIVE) return; event_errx(1, "%s: %p(fd %d) already on queue %x", __func__, ev, ev->ev_fd, queue); } if (~ev->ev_flags & EVLIST_INTERNAL) base->event_count++; //增加注冊事件數 ev->ev_flags |= queue; //改變event狀態 switch (queue) { //根據不同的輸入參數隊列,選擇在不同的事件集合中插入 case EVLIST_INSERTED: //I/O或Signal事件 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; } default: event_errx(1, "%s: unknown queue %x", __func__, queue); } }
event_queue_remove()
和event_queue_insert()相對應,這個函數主要根據不同的輸入參數,從不同的事件集合中刪除事件。
void event_queue_remove(struct event_base *base, struct event *ev, int queue) { if (!(ev->ev_flags & queue)) event_errx(1, "%s: %p(fd %d) not on queue %x", __func__, ev, ev->ev_fd, queue); if (~ev->ev_flags & EVLIST_INTERNAL) base->event_count--; ev->ev_flags &= ~queue; switch (queue) { case EVLIST_INSERTED: //I/O、Signal事件 TAILQ_REMOVE(&base->eventqueue, ev, ev_next); break; case EVLIST_ACTIVE: //活躍事件 base->event_count_active--; TAILQ_REMOVE(base->activequeues[ev->ev_pri], ev, ev_active_next); break; case EVLIST_TIMEOUT: //定時器事件 min_heap_erase(&base->timeheap, ev); break; default: event_errx(1, "%s: unknown queue %x", __func__, queue); } }
event_del()
libevent還提供了event_del()這個函數,該函數從直接刪除event事件,該函數就是主要通過調用event_queue_remove()函數完成刪除的功能。
另外,該函數還將event從I/O多路復用監聽的事件中刪除。
int event_del(struct event *ev) { struct event_base *base; const struct eventop *evsel; void *evbase; event_debug(("event_del: %p, callback %p", ev, ev->ev_callback)); /* An event without a base has not been added */ if (ev->ev_base == NULL) return (-1); base = ev->ev_base; evsel = base->evsel; evbase = base->evbase; assert(!(ev->ev_flags & ~EVLIST_ALL)); /* See if we are just active executing this event in a loop */ //計數清0 if (ev->ev_ncalls && ev->ev_pncalls) { /* Abort loop */ *ev->ev_pncalls = 0; } //根據event不同的狀態,從相應的event集合中刪除 if (ev->ev_flags & EVLIST_TIMEOUT) event_queue_remove(base, ev, EVLIST_TIMEOUT); if (ev->ev_flags & EVLIST_ACTIVE) event_queue_remove(base, ev, EVLIST_ACTIVE); if (ev->ev_flags & EVLIST_INSERTED) { event_queue_remove(base, ev, EVLIST_INSERTED); return (evsel->del(evbase, ev)); //從I/O多路復用監聽的事件中刪除 } return (0); }