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;     } }