Libevent源码分析——Libevent工作流程

在这里分析一下Libevent基本工作流程,深入理解一下libevent。
通常一个最简单的libevent应用流程图如下:
 
先了解一下struct event结构体

struct event结构体:

struct event {
    struct event_callback ev_evcallback;//事件回调函数结构体


    /* for managing timeouts */
    union {
        TAILQ_ENTRY(event) ev_next_with_common_timeout;
        size_t min_heap_idx;
    } ev_timeout_pos;
    evutil_socket_t ev_fd;//对于I/O事件,是文件描述符;对于signal事件,是信号值

    struct event_base *ev_base;

    union {//采用LIST_ENTRY双链表保存I/O事件和信号事件
        /* used for io events */
        struct {//用于I/O事件
            LIST_ENTRY (event) ev_io_next;
            struct timeval ev_timeout;
        } ev_io;


        /* used by signal events */
        struct {//用于信号事件
            LIST_ENTRY (event) ev_signal_next;
            short ev_ncalls;
            /* Allows deletes in callback */
            short *ev_pncalls;
        } ev_signal;
    } ev_;
    short ev_events;//记录监听的事件类型
    short ev_res;       /* result passed to event callback */
    struct timeval ev_timeout;//用于定时器指定超时时间
};
这里我的Libevent版本是libevent-2.1.10-stable,采用的是LIST_ENTRY双链表保存I/O事件和信号事件, 同一个文件描述符或者信号值对应的多个event会被连在一起,所有的被加入到event_base的event也会连在一起,所有被激活的event也会被连在一起, 所以会有多个链表和队列配合使用,在struct event重要的还有struct event_callback ev_evcallback回调函数结构体,定义如下:
struct event_callback {
    TAILQ_ENTRY(event_callback) evcb_active_next;//激活队列
    short evcb_flags;
    ev_uint8_t evcb_pri;    /* smaller numbers are higher priority */
    ev_uint8_t evcb_closure;
    /* allows us to adopt for different types of events */
        union {
        void (*evcb_callback)(evutil_socket_t, short, void *);
        void (*evcb_selfcb)(struct event_callback *, void *);
        void (*evcb_evfinalize)(struct event *, void *);
        void (*evcb_cbfinalize)(struct event_callback *, void *);
    } evcb_cb_union;
    void *evcb_arg;//传递到回调函数的参数
};

回调函数结构体包括回调函数指针,传到回调函数的参数、优先级等。

event_base_new()创建event_base:

event_base_new函数是由event_base_new_with_config函数实现。
 
struct event_base *
event_base_new(void)
{
    struct event_base *base = NULL;
    struct event_config *cfg = event_config_new();
    if (cfg) {
        base = event_base_new_with_config(cfg);
        event_config_free(cfg);
    }
    return base;
}
下面看event_base_new_with_config函数:
struct event_base *
event_base_new_with_config(const struct event_config *cfg)
{
    int i;
    struct event_base *base;
    int should_check_environment;


#ifndef EVENT__DISABLE_DEBUG_MODE
    event_debug_mode_too_late = 1;
#endif

    //使用calloc申请清零的内存区域
    if ((base = mm_calloc(1, sizeof(struct event_base))) == NULL) {
        event_warn("%s: calloc", __func__);
        return NULL;
    }
    ......
    TAILQ_INIT(&base->active_later_queue);
    ......
    evmap_io_initmap_(&base->io);
    evmap_signal_initmap_(&base->sigmap);
    event_changelist_init_(&base->changelist);

    base->evbase = NULL;
    ......
    for (i = 0; eventops[i] && !base->evbase; i++) {//选择IO复用结构体
        if (cfg != NULL) {
            /* determine if this backend should be avoided */
            if (event_config_is_avoided_method(cfg,
                eventops[i]->name))//禁用哪种多路复用
                continue;
            if ((eventops[i]->features & cfg->require_features)
                != cfg->require_features)//是否满足设置的特征
                continue;
        }


        /* also obey the environment variables */
        if (should_check_environment &&
            event_is_method_disabled(eventops[i]->name))
            continue;

        //找到一个满足条件的多路IO复用函数
        base->evsel = eventops[i];

        //初始化ev_base。并且会对信号监听的处理也进行初始化
        base->evbase = base->evsel->init(base);
    }
    if (base->evbase == NULL) {
        event_warnx("%s: no event mechanism available",
            __func__);
        base->evsel = NULL;
        event_base_free(base);
        return NULL;
    }


    if (evutil_getenv_("EVENT_SHOW_METHOD"))
        event_msgx("libevent using: %s", base->evsel->name);


    /* allocate a single active event queue */
    if (event_base_priority_init(base, 1) < 0) {
        event_base_free(base);
        return NULL;
    }
        /* prepare for threading */


#if !defined(EVENT__DISABLE_THREAD_SUPPORT) && !defined(EVENT__DISABLE_DEBUG_MODE)
    event_debug_created_threadable_ctx_ = 1;
#endif


#ifndef EVENT__DISABLE_THREAD_SUPPORT
    if (EVTHREAD_LOCKING_ENABLED() &&
        (!cfg || !(cfg->flags & EVENT_BASE_FLAG_NOLOCK))) {//配置是支持锁的
        int r;
        EVTHREAD_ALLOC_LOCK(base->th_base_lock, 0);//申请一个锁
        EVTHREAD_ALLOC_COND(base->current_event_cond);//申请一个线程条件变量
        r = evthread_make_base_notifiable(base);
        if (r<0) {
            event_warnx("%s: Unable to make base notifiable.", __func__);
            event_base_free(base);
            return NULL;
        }
    }
#endif

#ifdef _WIN32
    if (cfg && (cfg->flags & EVENT_BASE_FLAG_STARTUP_IOCP))
        event_base_start_iocp_(base, cfg->n_cpus_hint);
#endif
    return (base);
}
event_base_new_with_config会对event_base进行配置,选择使用哪一种多路复用,避免使用哪种多路复用,需满足的特征,线程是否支持锁等,下面是几个关于event_base配置的函数。
event_config_avoid_method()禁用某种多路复用,可以通过名称或者是 event_config的特征来禁用某种多路IO复用函数。
int event_config_avoid_method(struct event_config *cfg, const char *method)
{
    struct event_config_entry *entry = mm_malloc(sizeof(*entry));
    if (entry == NULL)
        return (-1);


    if ((entry->avoid_method = mm_strdup(method)) == NULL) {//strdup()在内部调用了malloc()为变量分配内存并将字符串拷贝
        mm_free(entry);
        return (-1);
    }

    TAILQ_INSERT_TAIL(&cfg->entries, entry, next);//插入到队列中

    return (0);
}
需要满足的特征可以设置成下面几种:
enum event_method_feature {
    /** Require an event method that allows edge-triggered events with EV_ET. */
    EV_FEATURE_ET = 0x01,//支持边沿触发
    EV_FEATURE_O1 = 0x02,//添加、删除、或者确定哪个事件激活这些动作的时间复杂度都为O(1),select、poll是不能满足这个特征的.epoll则满足
    EV_FEATURE_FDS = 0x04,//支持任意的文件描述符,而不能仅仅支持套接字
    EV_FEATURE_EARLY_CLOSE = 0x08//允许使用EV_CLOSED来检测连接关闭
};
以上的成员变量是通过event_config_require_features函数设置的,就是简单的赋值而已
int
event_config_require_features(struct event_config *cfg,int features)
{
    if (!cfg)
        return (-1);
    cfg->require_features = features;
    return (0);
}

event_new()创建event:

event_base创建之后就是event的创建,event_new主要的初始化工作交给另一个函数。event_new函数的工作只是创建一个struct event结构体,然后把它的参数原封不动地传给event_assign。

struct event *
event_new(struct event_base *base, evutil_socket_t fd, short events, void (*cb)(evutil_socket_t, short, void *), void *arg)
{
    struct event *ev;
    ev = mm_malloc(sizeof(struct event));
    if (ev == NULL)
        return (NULL);
    if (event_assign(ev, base, fd, events, cb, arg) < 0) {
        mm_free(ev);
        return (NULL);
    }
    return (ev);
}
下面是event_assign函数,初始化创建的event:
int
event_assign(struct event *ev, struct event_base *base, evutil_socket_t fd, short events, void (*callback)(evutil_socket_t, short,
void *), void *arg)
{
    if (!base)
        base = current_base;
    if (arg == &event_self_cbarg_ptr_)
        arg = ev;

    if (!(events & EV_SIGNAL))
        event_debug_assert_socket_nonblocking_(fd);
    event_debug_assert_not_added_(ev);

    ev->ev_base = base;
    ev->ev_callback = callback;
    ev->ev_arg = arg;
    ev->ev_fd = fd;
    ev->ev_events = events;
    ev->ev_res = 0;
    ev->ev_flags = EVLIST_INIT;
    ev->ev_ncalls = 0;
    ev->ev_pncalls = NULL;

    if (events & EV_SIGNAL) {
        if ((events & (EV_READ|EV_WRITE|EV_CLOSED)) != 0) {
            event_warnx("%s: EV_SIGNAL is not compatible with "
                "EV_READ, EV_WRITE or EV_CLOSED", __func__);
            return -1;
        }
        ev->ev_closure = EV_CLOSURE_EVENT_SIGNAL;
    } else {
        if (events & EV_PERSIST) {
            evutil_timerclear(&ev->ev_io_timeout);
            ev->ev_closure = EV_CLOSURE_EVENT_PERSIST;
        } else {
            ev->ev_closure = EV_CLOSURE_EVENT;
        }
    }

    min_heap_elem_init_(ev);

    if (base != NULL) {
        /* by default, we put new events into the middle priority */
        ev->ev_pri = base->nactivequeues / 2;
    }
    event_debug_note_setup_(ev);

    return 0;
}
主要是对上面说的struct event结构体初始化赋值,绑定base,回调函数,回调函数参数,文件描述符以及标志位,中间判断持续化事件,并且不允许监听信号后还监听读写等, event结构体的变量ev_flags的值是EVLIST_INIT,指明了event结构体的状态。
 
//在event_struct.h里
#define EVLIST_TIMEOUT      0x01
#define EVLIST_INSERTED     0x02
#define EVLIST_SIGNAL       0x04
#define EVLIST_ACTIVE       0x08
#define EVLIST_INTERNAL     0x10
#define EVLIST_ACTIVE_LATER 0x20
#define EVLIST_FINALIZING   0x40
#define EVLIST_INIT     0x80

#define EVLIST_ALL          0xff

event_add将event加入到event_base中:

创建完一个event结构体后,就会调用event_add将event加入到event_base中,它和前面的函数一样,内部调用其他函数完成工作。
int
event_add(struct event *ev, const struct timeval *tv)
{
    int res;

    if (EVUTIL_FAILURE_CHECK(!ev->ev_base)) {
        event_warnx("%s: event has no event_base set.", __func__);
        return -1;
    }
    EVBASE_ACQUIRE_LOCK(ev->ev_base, th_base_lock);//加锁

    res = event_add_nolock_(ev, tv, 0);
    
    EVBASE_RELEASE_LOCK(ev->ev_base, th_base_lock);//解锁

    return (res);
}
event_add_nolock_是event_add内部实现函数,event_add函数只是对event_base加了锁,然后调用event_add_nolock_函数完成工作。所以函数event_add是线程安全的。
int
event_add_nolock_(struct event *ev, const struct timeval *tv,
    int tv_is_absolute)
{
    struct event_base *base = ev->ev_base;
    int res = 0;
    int notify = 0;

    EVENT_BASE_ASSERT_LOCKED(base);//检查是否上锁
    event_debug_assert_is_setup_(ev);
    .......
    
    if ((ev->ev_events & (EV_READ|EV_WRITE|EV_CLOSED|EV_SIGNAL)) &&
        !(ev->ev_flags & (EVLIST_INSERTED|EVLIST_ACTIVE|EVLIST_ACTIVE_LATER))) {
        if (ev->ev_events & (EV_READ|EV_WRITE|EV_CLOSED))
            res = evmap_io_add_(base, ev->ev_fd, ev);//加入io队列
        else if (ev->ev_events & EV_SIGNAL)
            res = evmap_signal_add_(base, (int)ev->ev_fd, ev);//加入信号队列
        if (res != -1)
            event_queue_insert_inserted(base, ev);
        if (res == 1) {
            /* evmap says we need to notify the main thread. */
            notify = 1;
            res = 0;
        }
    }
        return (res);
}
event_add_nolock_ 调用evmap_io_add_和evmap_signal_add_,把有相同文件描述符fd和信号值sig的event连在一个队列里面。
 
/* return -1 on error, 0 on success if nothing changed in the event backend,
* and 1 on success if something did. */
int
evmap_io_add_(struct event_base *base, evutil_socket_t fd, struct event *ev)
{
    const struct eventop *evsel = base->evsel;
    struct event_io_map *io = &base->io;
    struct evmap_io *ctx = NULL;
    int nread, nwrite, nclose, retval = 0;
    short res = 0, old = 0;
    struct event *old_ev;


    EVUTIL_ASSERT(fd == ev->ev_fd);


    if (fd < 0)
        return 0;
#ifndef EVMAP_USE_HT
    if (fd >= io->nentries) {
        if (evmap_make_space(io, fd, sizeof(struct evmap_io *)) == -1)
            return (-1);
    }
#endif
    GET_IO_SLOT_AND_CTOR(ctx, io, fd, evmap_io, evmap_io_init,
                         evsel->fdinfo_len);

    nread = ctx->nread;
    nwrite = ctx->nwrite;
    nclose = ctx->nclose;

    if (nread)
        old |= EV_READ;
    if (nwrite)
        old |= EV_WRITE;
    if (nclose)
        old |= EV_CLOSED;

    if (ev->ev_events & EV_READ) {//记录是不是第一次。如果是第一次,那么就说明该fd还没被加入到多路IO复用中。
        if (++nread == 1)//则需要加入到像select、epoll这些函数中.
            res |= EV_READ;
    }
    if (ev->ev_events & EV_WRITE) {
        if (++nwrite == 1)
            res |= EV_WRITE;
    }
    if (ev->ev_events & EV_CLOSED) {
        if (++nclose == 1)
            res |= EV_CLOSED;
    }

    if (EVUTIL_UNLIKELY(nread > 0xffff || nwrite > 0xffff || nclose > 0xffff)) {
        event_warnx("Too many events reading or writing on fd %d",
            (int)fd);
        return -1;
    }
    if (EVENT_DEBUG_MODE_IS_ON() &&
        (old_ev = LIST_FIRST(&ctx->events)) &&
        (old_ev->ev_events&EV_ET) != (ev->ev_events&EV_ET)) {
        event_warnx("Tried to mix edge-triggered and non-edge-triggered"
            " events on fd %d", (int)fd);
        return -1;
    }

    if (res) {//把fd加入到多路IO复用中。
        void *extra = ((char*)ctx) + sizeof(struct evmap_io);
        /* XXX(niels): we cannot mix edge-triggered and
         * level-triggered, we should probably assert on
         * this. */
        if (evsel->add(base, ev->ev_fd,
            old, (ev->ev_events & EV_ET) | res, extra) == -1)
            return (-1);
        retval = 1;
    }
    ctx->nread = (ev_uint16_t) nread;//把次数记录下来。
    ctx->nwrite = (ev_uint16_t) nwrite;
    ctx->nclose = (ev_uint16_t) nclose;
    LIST_INSERT_HEAD(&ctx->events, ev, ev_io_next);

    return (retval);
}
  nread、nwrite和nclose值为1说明是第一次监听对应的事件。需要把这个fd添加到多路IO复用函数中。调用evsel->add()完成fd与select、poll、epoll之类的多路IO复用函数的相关联,这里的add()是函数指针,下面讲到struct eventop结构体的时候就能看到。
int
evmap_signal_add_(struct event_base *base, int sig, struct event *ev)
{
    const struct eventop *evsel = base->evsigsel;
    struct event_signal_map *map = &base->sigmap;
    struct evmap_signal *ctx = NULL;
        
    if (sig < 0 || sig >= NSIG)
        return (-1);
            
    if (sig >= map->nentries) {
        if (evmap_make_space(
            map, sig, sizeof(struct evmap_signal *)) == -1)
            return (-1);
    }
    GET_SIGNAL_SLOT_AND_CTOR(ctx, map, sig, evmap_signal, evmap_signal_init,
        base->evsigsel->fdinfo_len);


    if (LIST_EMPTY(&ctx->events)) {
        if (evsel->add(base, ev->ev_fd, 0, EV_SIGNAL, NULL)
            == -1)
            return (-1);
    }


    LIST_INSERT_HEAD(&ctx->events, ev, ev_signal_next);
    return (1);
}
信号事件不能跟IO事件读写事件一块监听,信号事件通过捕捉函数并创建管道(Libevent用的是 socketpair()创建一对无名 相互连接的套接字),多路复用通过监听管道来监听事件的发生,所以信号采用单独采用evmap_signal_add_出来注册到base,当链表为空的时候也是用evsel->add加入多路复用监听,接着加入到链表首。

event_base_dispatch循环处理event事件:

事件添加完毕之后,进入event_base_dispatch函数循环处理事件。跟之前的一样,该函数内部调用event_base_loop完成工作。
int
event_loop(int flags)
{
    return event_base_loop(current_base, flags);
}


int
event_base_loop(struct event_base *base, int flags)
{
    const struct eventop *evsel = base->evsel;
    struct timeval tv;
    struct timeval *tv_p;
    int res, done, retval = 0;

    /* Grab the lock.  We will release it inside evsel.dispatch, and again
     * as we invoke user callbacks. */
    EVBASE_ACQUIRE_LOCK(base, th_base_lock);//上锁

    if (base->running_loop) {//如果已经是循环状态
        event_warnx("%s: reentrant invocation.  Only one event_base_loop"
            " can run on each event_base at once.", __func__);
        EVBASE_RELEASE_LOCK(base, th_base_lock);
        return -1;
    }

    base->running_loop = 1;
    .......
    while (!done) {
        .......
        res = evsel->dispatch(base, tv_p);//调用多路IO复用函数,对event进行监听,并且把满足条件的event放到event_base的激活队列中
        if (res == -1) {
            event_debug(("%s: dispatch returned unsuccessfully.",
                __func__));
            retval = -1;
            goto done;
        }
        .......
        if (N_ACTIVE_CALLBACKS(base)) {
            int n = event_process_active(base);//遍历这个激活队列的所有event,逐个调用对应的回调函数
            if ((flags & EVLOOP_ONCE)
                && N_ACTIVE_CALLBACKS(base) == 0
                && n != 0)
                done = 1;
        } else if (flags & EVLOOP_NONBLOCK)
            done = 1;
    }
    event_debug(("%s: asked to terminate loop.", __func__));


done:
    clear_time_cache(base);
    base->running_loop = 0;

    EVBASE_RELEASE_LOCK(base, th_base_lock);//释放锁
    return (retval);
}
这里重要的是evsel->dispatch和event_process_active两个函数, evsel->dispatch 对event进行监听,并且把满足条件的event放到event_base的激活队列中。 event_process_active遍历这个激活队列的所有event,逐个调用对应的回调函数。
    先来看看struct eventop结构体,之前的event_add调用了evsel->add()去加入到多路复用去监听,而这个evsel是struct eventop结构体指针。
 
const struct eventop *evsel = base->evsel;

/** Structure to define the backend of a given event_base. */
struct eventop {
    /** The name of this backend. */
    const char *name;
    /** Function to set up an event_base to use this backend.  It should
     * create a new structure holding whatever information is needed to
     * run the backend, and return it.  The returned pointer will get
     * stored by event_init into the event_base.evbase field.  On failure,
     * this function should return NULL. */
    void *(*init)(struct event_base *);
    int (*add)(struct event_base *, evutil_socket_t fd, short old, short events, void *fdinfo);
    /** As "add", except 'events' contains the events we mean to disable. */
    int (*del)(struct event_base *, evutil_socket_t fd, short old, short events, void *fdinfo);
    /** Function to implement the core of an event loop.  It must see which
        added events are ready, and cause event_active to be called for each
        active event (usually via event_io_active or such).  It should
        return 0 on success and -1 on error.
     */
    int (*dispatch)(struct event_base *, struct timeval *);
    /** Function to clean up and free our data from the event_base. */
    void (*dealloc)(struct event_base *);
    /** Flag: set if we need to reinitialize the event base after we fork.
     */
    int need_reinit;
    /** Bit-array of supported event_method_features that this backend can
     * provide. */
    enum event_method_feature features;
    /** Length of the extra information we should record for each fd that
        has one or more active events.  This information is recorded
        as part of the evmap entry for each fd, and passed as an argument
        to the add and del functions above.
     */
    size_t fdinfo_len;
};
int (*dispatch)(struct event_base *, struct timeval *);是个函数指针,它的实现包含多路IO复用函数。这里拿poll多路复用来分析。
static int
poll_dispatch(struct event_base *base, struct timeval *tv)
{
    int res, i, j, nfds;
    long msec = -1;
    struct pollop *pop = base->evbase;
    struct pollfd *event_set;

    poll_check_ok(pop);

    nfds = pop->nfds;
    .....
    EVBASE_RELEASE_LOCK(base, th_base_lock);//解锁
    res = poll(event_set, nfds, msec);//调用poll多路复用监听


    EVBASE_ACQUIRE_LOCK(base, th_base_lock);//再次上锁
    if (res == -1) {
        if (errno != EINTR) {
            event_warn("poll");
            return (-1);
        }
        return (0);
    }

    event_debug(("%s: poll reports %d", __func__, res));

    if (res == 0 || nfds == 0)
        return (0);

    i = evutil_weakrand_range_(&base->weakrand_seed, nfds);
    for (j = 0; j < nfds; j++) {
        int what;
        if (++i == nfds)
            i = 0;
        what = event_set[i].revents;
        if (!what)
            continue;

        res = 0;
        /* If the file gets closed notify */
        if (what & (POLLHUP|POLLERR|POLLNVAL))
            what |= POLLIN|POLLOUT;
        if (what & POLLIN)
            res |= EV_READ;
        if (what & POLLOUT)
            res |= EV_WRITE;
        if (res == 0)
            continue;

        evmap_io_active_(base, event_set[i].fd, res);//把这个ev放到激活队列中
    }
    return (0);
}
poll返回时,如果事件发生,就调用evmap_io_active(base, event_set[i].fd, res);把fd对应的event放到event_base的激活event队列中。下面是evmap_io_active_的代码。
 
void
evmap_io_active_(struct event_base *base, evutil_socket_t fd, short events)
{
    struct event_io_map *io = &base->io;
    struct evmap_io *ctx;
    struct event *ev;
    
#ifndef EVMAP_USE_HT
    if (fd < 0 || fd >= io->nentries)
        return;
#endif
    GET_IO_SLOT(ctx, io, fd, evmap_io);
    
    if (NULL == ctx)
        return;
    LIST_FOREACH(ev, &ctx->events, ev_io_next) {
        if (ev->ev_events & events)
            event_active_nolock_(ev, ev->ev_events & events, 1);
    }
}

void
event_active_nolock_(struct event *ev, int res, short ncalls)
{
    struct event_base *base;

    ......

    event_callback_activate_nolock_(base, event_to_event_callback(ev));
}

int
event_callback_activate_nolock_(struct event_base *base,
    struct event_callback *evcb)
{
    int r = 1;

    if (evcb->evcb_flags & EVLIST_FINALIZING)
        return 0;
        ......
    event_queue_insert_active(base, evcb);//最终调用这个函数加入到激活队列里

    return r;
}

static void
event_queue_insert_active(struct event_base *base, struct event_callback *evcb)
{
    EVENT_BASE_ASSERT_LOCKED(base);


    if (evcb->evcb_flags & EVLIST_ACTIVE) {
        /* Double insertion is possible for active events */
        return;
    }

    INCR_EVENT_COUNT(base, evcb->evcb_flags);

    evcb->evcb_flags |= EVLIST_ACTIVE;

    base->event_count_active++;//队列event激活数加一
    MAX_EVENT_COUNT(base->event_count_active_max, base->event_count_active);
    EVUTIL_ASSERT(evcb->evcb_pri < base->nactivequeues);
    TAILQ_INSERT_TAIL(&base->activequeues[evcb->evcb_pri],//evcb->evcb_pri指定插入哪个优先级队列
        evcb, evcb_active_next);//将event插入到对应对应优先级的激活队列中
}
上面几个函数最终将fd对应的event插入到激活队列中。因为Libevent还对事件处理有优先级,所以是激活数组队列,而不是只有一个激活队列。

处理激活列表中的event:

//event-internal.h
#define N_ACTIVE_CALLBACKS(base)                    \
    ((base)->event_count_active)
当队列有被激活的event时,调用event_process_active遍历这个激活队列的所有event,逐个调用对应的回调函数。
static int
event_process_active(struct event_base *base)
{
    /* Caller must hold th_base_lock */
    struct evcallback_list *activeq = NULL;
    int i, c = 0;
    const struct timeval *endtime;
    struct timeval tv;
    const int maxcb = base->max_dispatch_callbacks;
    const int limit_after_prio = base->limit_callbacks_after_prio;
    .....
    for (i = 0; i < base->nactivequeues; ++i) {//从高优先级到低优先级遍历优先级数组。
        if (TAILQ_FIRST(&base->activequeues[i]) != NULL) {//对于特定的优先级,遍历该优先级的所有激活event
            base->event_running_priority = i;
            activeq = &base->activequeues[i];
            if (i < limit_after_prio)
                c = event_process_active_single_queue(base, activeq,
                    INT_MAX, NULL);
            else
                c = event_process_active_single_queue(base, activeq,
                    maxcb, endtime);
            if (c < 0) {
                goto done;
            } else if (c > 0)
                break; /* Processed a real event; do not
                    * consider lower-priority events */
            /* If we get here, all of the events we processed
             * were internal.  Continue. */
        }
    }
done:
    base->event_running_priority = -1;

    return c;
}



static int
event_process_active_single_queue(struct event_base *base,
    struct evcallback_list *activeq,
    int max_to_process, const struct timeval *endtime)
{
    struct event_callback *evcb;
    int count = 0;


    EVUTIL_ASSERT(activeq != NULL);


    for (evcb = TAILQ_FIRST(activeq); evcb; evcb = TAILQ_FIRST(activeq)) {
        struct event *ev=NULL;
        if (evcb->evcb_flags & EVLIST_INIT) {
            ev = event_callback_to_event(evcb);


            if (ev->ev_events & EV_PERSIST || ev->ev_flags & EVLIST_FINALIZING)//如果是持续状态事件
                event_queue_remove_active(base, evcb);//仅仅从激活队列中移除
            else//不是的话,那么就要把这个event删除掉。
                event_del_nolock_(ev, EVENT_DEL_NOBLOCK);
                .....
        } else {
            event_queue_remove_active(base, evcb);
            event_debug(("event_process_active: event_callback %p, "
                "closure %d, call %p",
                evcb, evcb->evcb_closure, evcb->evcb_cb_union.evcb_callback));
        }
                .....

        switch (evcb->evcb_closure) {
                .....
        case EV_CLOSURE_EVENT: {
            void (*evcb_callback)(evutil_socket_t, short, void *);
            short res;
            EVUTIL_ASSERT(ev != NULL);
            evcb_callback = *ev->ev_callback;//用户定义的回调函数
            res = ev->ev_res;
            EVBASE_RELEASE_LOCK(base, th_base_lock);
            evcb_callback(ev->ev_fd, res, ev->ev_arg);//调用回调函数
        }
        break;
        .....
        default:
            EVUTIL_ASSERT(0);
        }

        EVBASE_ACQUIRE_LOCK(base, th_base_lock);
    }
    return count;
}
上面的代码,从高到低优先级遍历激活event优先级数组。对于激活的event,先调用event_queue_remove_active从激活队列中删除掉,跟清处中断差不多。然后再对这个event调用其回调函数。event_queue_remove_active函数的调用会改变event结构体的ev_flags变量的值,就又可以等待下一次事件的到来了。

抛开内部的数据结构队列、链表不看最后整个工作流程大致就是这样:

 
 
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值