libevent源码分析-event

event结构

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

struct event {
    TAILQ_ENTRY(event) ev_active_next;
    TAILQ_ENTRY(event) ev_next;
    /* for managing timeouts */
    union {
        TAILQ_ENTRY(event) ev_next_with_common_timeout;
        int min_heap_idx;
    } ev_timeout_pos;
    evutil_socket_t ev_fd;

    struct event_base *ev_base;

    union {
        /* used for io events */
        struct {
            TAILQ_ENTRY(event) ev_io_next;
            struct timeval ev_timeout;
        } ev_io;

        /* used by signal events */
        struct {
            TAILQ_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 */
    short ev_flags;
    ev_uint8_t ev_pri;  /* smaller numbers are higher priority */
    ev_uint8_t ev_closure;
    struct timeval ev_timeout;

    /* allows us to adopt for different types of events */
    void (*ev_callback)(evutil_socket_t, short, void *arg);
    void *ev_arg;
};

TAILQ_ENTRY是宏定义,展开后为双向链表中的指针结点。

#define TAILQ_ENTRY(type)                       \
struct {                                \
    struct type *tqe_next;  /* next element */          \
    struct type **tqe_prev; /* address of previous next element */  \
}

这个指针信息用来管理event事件。event事件在Reactor中,用链表存储。
ev_active_next是激活事件在激活事件链表中的位置。Reactor中有激活事件列表,程序会遍历这个列表,执行响应的处理程序。
ev_next保存了当前事件在注册链表中的位置。
ev_timeout_pos是union,它是定时器或在超时链表中的位置。
ev_fd时event管理的fd,可以时socket或signal。
ev_base是event所在的Reactor。
_ev是个union,event可能是IO事件,也可能时signal事件。用一个union表示,节省了空间。
ev_events表明监听事件的类型。可以是以下事件

#define EV_TIMEOUT 0x01  //定时器事件
#define EV_READ  0x02  //IO读事件
#define EV_WRITE 0x04  //IO写事件
#define EV_SIGNAL 0x08  //信号事件
#define EV_PERSIST 0x10 //永久事件

ev_flags表示当前event的状态,值如下

#define EVLIST_TIMEOUT  0x01 //在time堆中
#define EVLIST_INSERTED 0x02  //已经添加到事件列表中
#define EVLIST_SIGNAL   0x04 //
#define EVLIST_ACTIVE   0x08 //在激活链表中
#define EVLIST_INTERNAL 0x10 
#define EVLIST_INIT 0x80  //已经初始化

ev_pri表示优先级。数字越小,优先级越高,可以调用函数设置

int event_priority_set(struct event *ev, int pri)

ev_closure根据其类型来调用不同回调函数。
ev_callback是event的回调函数。三个参数分别为ev_fdev_eventsev_arg

event相关接口

有关event的接口定义在event.c中。在前面程序中用到了

event_set(&listenEvent, sock, EV_READ|EV_PERSIST, handleAccept, NULL);
event_base_set(base, &listenEvent);
event_add(&listenEvent, NULL);

其中

void
event_set(struct event *ev, evutil_socket_t fd, short events,
      void (*callback)(evutil_socket_t, short, void *), void *arg)

功能为设置event的参数。
ev表示event事件。
fd表示和事件相关联的fd。
callback是函数指针,表示事件处理程序。
arg为ev_arg的值。

int
event_base_set(struct event_base *base, struct event *ev)

功能为将event和Reactor关联起来。
base是event所在的Reactor。

int
event_add(struct event *ev, const struct timeval *tv)

功能为将event添加到Reactor中。
tv是超时时间。

Libevent对event的管理

这里写图片描述
借助别人博客的图,形象的看一下Reactor中,怎么管理event。在反应堆event_base中有相应的链表和堆,来管理event事件。不同的事件对应不同指针/字段,IO事件对应ev_next,信号事件对应ev_signal_next,定时器事件对应min_head_idx,激活后的事件对应ev_active_next。当事件激活后,把事件转移到list[priority]队列,之后对事件一一处理。

参考:
深入理解TAILQ队列

linux内核分析–内核中的数据结构之双链表(一)

libevent源码深度剖析五——libevent的核心:事件event

http://www.wangafu.net/~nickm/libevent-2.0/doxygen/html/structevent.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
libevent是一个事件触发的网络库,适用于windows、linux、bsd等多种平台,内部使用select、epoll、kqueue等系统调用管理事件机制。著名分布式缓存软件memcached也是libevent based,而且libevent在使用上可以做到跨平台,而且根据libevent官方网站上公布的数据统计,似乎也有着非凡的性能。 编辑本段 详细   编译库代码,编译脚本会判断OS支持哪种类型的事件机制(select、epoll或kqueue),然后条件编译相应代码,供上层使用的接口仍然是保持统一的(否则也不能所谓的跨平台了)。在linux redhat as 4 u 2 上编译相当容易,configure以后make,make install就可以了,windows上编译似乎有点小麻烦,不过稍微改点东西也就通过了。   从代码中看,libevent支持用户使用三种类型的事件,分别是网络IO、定时器、信号三种,在定时器的实现上使用了RB tree的数据结构,以达到高效查找、排序、删除定时器的目的,网络IO上,主要关注了一下linux上的epoll(因为目前的开发主要在linux平台),结果发现libevent的epoll居然用的EPOLLLT,水平触发的方式用起来比较方便,不容易出错,但是在效率上可能比EPOLLET要低一些。   跟网络无关的,libevent也有一些缓冲区管理的函数,而且是c风格的函数,实用性不是太大。libevent没有提供缓存的函数。   虽然libevent实用上的价值不大,但它提供的接口形式还是不错的,实现类似的lib的时候仍然是可以参考的。   Libevent定时器的数据结构自version 1.4起已由红黑树改为最小堆(Min Heap),以提高效率;网络IO和信号的数据结构采用了双向链表(TAILQ)。在实现上主要有3种链表: EVLIST_INSERTED, EVLIST_ACTIVE, EVLIST_TIMEOUT,一个ev在这3种链表之间被插入或删除,处于EVLIST_ACTIVE链表中的ev最后将会被调度执行。   Libevent提供了DNS,HTTP Server,RPC等组件,HTTP Server可以说是Libevent的经典应用。从http.c可看到Libevent的很多标准写法。写非阻塞式的HTTP Server很容易将socket处理与HTTP协议处理纠缠在一起,Libevent在这点上似乎也有值得推敲的地方。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值