libevent(三)event_base

libevent能够处理三种事件: I/O、定时器、信号。

event_base

    统一管理所有事件。

struct event_base {
    const struct eventop *evsel;    // backend
    void *evbase;                   /** Pointer to backend-specific data. */

    const struct eventop *evsigsel; // signal backend
    struct evsig_info sig;          /** Data to implement the common signal handelr code. */
    
    int event_count;                // 事件总数
    int event_count_active;         // 激活事件总数
    
    struct event_list eventqueue;   // 存储所有事件,但不包括定时器事件
    struct event_io_map io;         // 存储I/O事件
    struct event_signal_map sigmap; // 存储信号事件
    struct min_heap timeheap;       // 存储定时器事件
    
    /* Active event management. */
    /** An array of nactivequeues queues for active events (ones that
     * have triggered, and whose callbacks need to be called).  Low
     * priority numbers are more important, and stall higher ones.
     */
    struct event_list *activequeues;
    /** The length of the activequeues array */
    int nactivequeues;
    
    ...
};

eventop

    用于描述event_base的底层实现机制

/** Structure to define the backend of a given event_base. */
struct eventop {
    const char *name;
    void *(*init)(struct event_base *);
    int (*add)(struct event_base *, evutil_socket_t fd, short old, short events, void *fdinfo);
    int (*del)(struct event_base *, evutil_socket_t fd, short old, short events, void *fdinfo);
    int (*dispatch)(struct event_base *, struct timeval *);
    void (*dealloc)(struct event_base *);
    int need_reinit;
    enum event_method_feature features;
    size_t fdinfo_len;
};

libevent支持多种平台,因此定义了一个全局数组来存放多个eventop。

/* Array of backends in order of preference. */
static const struct eventop *eventops[] = {
#ifdef _EVENT_HAVE_EVENT_PORTS
    &evportops,
#endif
#ifdef _EVENT_HAVE_WORKING_KQUEUE
    &kqops,
#endif
#ifdef _EVENT_HAVE_EPOLL
    &epollops,
#endif
#ifdef _EVENT_HAVE_DEVPOLL
    &devpollops,
#endif
#ifdef _EVENT_HAVE_POLL
    &pollops,
#endif
#ifdef _EVENT_HAVE_SELECT
    &selectops,
#endif
#ifdef WIN32
    &win32ops,
#endif
    NULL
};

Linux平台的I/O多路复用机制是epoll,对应epollops。

const struct eventop epollops = {
    "epoll",
    epoll_init,
    epoll_nochangelist_add,
    epoll_nochangelist_del,
    epoll_dispatch,
    epoll_dealloc,
    1, /* need reinit */
    EV_FEATURE_ET|EV_FEATURE_O1,
    0
};

在event_base中,evsigsel也对应一个后端,这个后端用于信号处理。

值得注意的是这个成员的初始化时间:

int
evsig_init(struct event_base *base)
{
    /*
     * Our signal handler is going to write to one end of the socket
     * pair to wake up our event loop.  The event loop then scans for
     * signals that got delivered.
     */
    if (evutil_socketpair(
            AF_UNIX, SOCK_STREAM, 0, base->sig.ev_signal_pair) == -1) {
#ifdef WIN32
        /* Make this nonfatal on win32, where sometimes people
           have localhost firewalled. */
        event_sock_warn(-1, "%s: socketpair", __func__);
#else
        event_sock_err(1, -1, "%s: socketpair", __func__);
#endif
        return -1;
    }

    evutil_make_socket_closeonexec(base->sig.ev_signal_pair[0]);
    evutil_make_socket_closeonexec(base->sig.ev_signal_pair[1]);
    base->sig.sh_old = NULL;
    base->sig.sh_old_max = 0;

    evutil_make_socket_nonblocking(base->sig.ev_signal_pair[0]);
    evutil_make_socket_nonblocking(base->sig.ev_signal_pair[1]);

    event_assign(&base->sig.ev_signal, base, base->sig.ev_signal_pair[1],
        EV_READ | EV_PERSIST, evsig_cb, base);

    base->sig.ev_signal.ev_flags |= EVLIST_INTERNAL;
    event_priority_set(&base->sig.ev_signal, 0);

    base->evsigsel = &evsigops;

    return 0;
}

 evsigops结构如下:

static const struct eventop evsigops = {
    "signal",
    NULL,
    evsig_add,
    evsig_del,
    NULL,
    NULL,
    0, 0, 0
};

 

posted @ 2017-10-17 10:38  Sawyer Ford  阅读(730)  评论(0编辑  收藏  举报