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()

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);
}
时间: 2024-07-30 16:57:34

Libevent源码分析—event_add()的相关文章

[libevent源码分析] event_add

event_add 把event往当前event中的ev_base追加,如果需要定时,那么tv不能为空 int event_add(struct event *ev, const struct timeval *tv) { struct event_base *base = ev->ev_base; //event_add 会把event加入到他的ev_base成员里 const struct eventop *evsel = base->evsel; //对应linux的epoll相关函数

Libevent源码分析-timer和signal处理

timer处理 Signal处理 timerfd和signalfd timerfd signalfd timer处理 在Libevent源码分析-event处理流程中,使用了定时器,来看一下源码: evtimer_set(&ev, time_cb, NULL);//设置定时器事件 其中evtimer_set是个宏定义 #define evtimer_set(ev, cb, arg) event_set((ev), -1, 0, (cb), (arg)) //event_set原型 void ev

【转】libevent源码分析

libevent源码分析 转自:http://www.cnblogs.com/hustcat/archive/2010/08/31/1814022.html 这两天没事,看了一下Memcached和libevent的源码,做个小总结. 1.入门 1.1.概述Libevent是一个用于开发可扩展性网络服务器的基于事件驱动(event-driven)模型的网络库.Libevent有几个显著的亮点: (1)事件驱动(event-driven),高性能:(2)轻量级,专注于网络,不如 ACE 那么臃肿庞

Libevent源码分析 (1) hello-world

Libevent源码分析 (1) hello-world ⑨月份接触了久闻大名的libevent,当时想读读源码,可是由于事情比较多一直没有时间,现在手头的东西基本告一段落了,我准备读读libevent的源码,凡是我觉得有必要的内容均一一记录,与君共勉. 首先要说说什么是libevent: libevent是一个事件通知库,libevent API提供一种机制使得我们可以在一个文件描述符(file descriptor)发生特定事件时或者timeout发生时执行指定的回调函数.libevent意

libevent源码分析-event

event结构 event相关接口 Libevent对event的管理 event结构 event是Reactor模式中的最重要的组件.它包含了了一个句柄fd,并设置监听这个句柄上的哪些事件(读/写等),设置了对应的函数指针,在事件到来时,回调函数指针来处理事件. 先看一下event的结构.它位于include/event2/event_struct.h中 struct event { TAILQ_ENTRY(event) ev_active_next; TAILQ_ENTRY(event) e

[libevent源码分析] event_init

libevent采用的是经典的reactor网络框架,集成了信号.定时.网络事件于一体 首先对event_init进行源码剖析 event_init 主要创建event_base对象, struct event_base { const struct eventop *evsel; //lievent支持select epoll kequeue..等网络api,包括init.add.del.dispatch的接口,每种网络框架都支持 void *evbase; //支持相应网络api的 结构对象

[libevent源码分析] event_set

libevent使用event来封装网络事件回调,参数.fd...等一些信息,函数很简单 void event_set(struct event *ev, int fd, short events, void (*callback)(int, short, void *), void *arg) { /* Take the current base - caller needs to set the real base later */ ev->ev_base = current_base; /

[libevent源码分析] event_base_dispatch

分析下事件循环 event_base_dispatch int event_base_dispatch(struct event_base *event_base) { return (event_base_loop(event_base, 0)); } int event_base_loop(struct event_base *base, int flags) { const struct eventop *evsel = base->evsel; void *evbase = base->

libevent源码分析:event_add、event_del

event_add.event_del两个函数分别是使event生效和失效的,下面就来看一下两个函数的实现. event_add 1 int 2 event_add(struct event *ev, const struct timeval *tv) 3 { 4 int res; 5 6 if (EVUTIL_FAILURE_CHECK(!ev->ev_base)) { 7 event_warnx("%s: event has no event_base set.", __fu