首页 > 代码库 > Libevent源码分析—event_add()

Libevent源码分析—event_add()

接下来就是将已经初始化的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()
intevent_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中插入
voidevent_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()相对应,这个函数主要根据不同的输入参数,从不同的事件集合中删除事件。
voidevent_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多路复用监听的事件中删除。
intevent_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);}

 

 

Libevent源码分析—event_add()