libevent 代碼閱讀筆記

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;     } }
相關文章
相關標籤/搜索