libevent高性能网络库源码分析——事件(event)及其接口(三)

libevent的结构

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; //对于I/O事件,是绑定的文件描述符;对于signal事件,是绑定的信号

    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; //事件就绪执行时,调用ev_callback的次数
            /* Allows deletes in callback */
            short *ev_pncalls; //指针,通常指向 ev_ncalls 或者为 NULL
        } ev_signal;
    } _ev;

    short ev_events; //event的事件类型
    short ev_res;           //事件的回调函数的执行结果
    short ev_flags;         //用于标记 event信息的字段,表明事件当前的状态
    ev_uint8_t ev_pri;      //事件的优先级设置,值越小,则优先级越高
    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;
};

其中主要字段说明如下:

1 . ev_next,ev_active_next 和 ev_signal_next 都是双向链表节点指针;通过双向链表对不同类型、不同状态的事件进行管理。libevent 使用双向链表保存所有注册的 I/O和 Signal 事件,ev_next 指向“已注册事件链表”,其包含了所有的已注册的事件; ev_io_next 指向I/O事件在I/O事件链表中的位置; ev_signal_next 就是 signal 事件在 signal 事件链表中的位置; ev_active_next指向已激活的事件在active链表中的位置。


这里写图片描述

2 . ev_events
即event注册的事件类型

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

3 . ev_flags
某个event可在多个队列中,通过标志来标记event的当前所在的位置,状态值:

#define EVLIST_TIMEOUT  0x01 //event在min_heap中
#define EVLIST_INSERTED 0x02 //event在已注册的事件链表中
#define EVLIST_SIGNAL   0x04 //event在event_signal_map中
#define EVLIST_ACTIVE   0x08 //event在激活的链表中
#define EVLIST_INTERNAL 0x10 //内部使用标记
#define EVLIST_INIT     0x80 //event已经初始化

注:event_io_map 容器没有专门标志, 如果 ev_event 有 EV_READ|EV_WRITE, event_add 后一定在 event_io_map 中。且EV_READ|EV_WRITE不能和signal同时出现。

4 . 其他

  • min_heap
    基于小根堆管理超时event,其中min_heap[0] 存放在第一个(最快)要超时的 event (的指针).
  • event_io_map
    一个 hashtable, key是fd, value是fd对应的事件list. 如果对一个fd监控可读或可写时间的话, 那么这个fd绑定的 event 就会被加入到 value 的list 中. 同理如果 event_del 一个监控可读|可写事件的event, 那么也会从 key(fd)->value->list 中删除对应事件.
  • event_signal_map
    与event_io_map 相似,也可以认为是一个 hashtable, key 是 signal number(signo), value 是这个 signo 对应的 event list.(一个信号可以对应多个event, 信号发生后会挨个调用这些event 的回调).

event相关接口

1 . 创建事件 (event_new)
主要完成event的空间分配,

struct event * event_new(struct event_base *base,
                        evutil_socket_t fd,
                        void (*cb)(evutil_socket_t, short, void *),
                        void *arg)
{
    struct event *ev;
    // 分配new event的空间
    ev = mm_malloc(sizeof(struct event));
    ...
    // event的参数赋值
    ev->ev_base = base;         // 依附的event_base
    ev->ev_callback = callback; // 设置回调函数
    ev->ev_arg = arg;
    ev->ev_fd = fd;
    ev->ev_events = events;     // 该event注册的事件类型
    ev->ev_res = 0;
    ev->ev_flags = EVLIST_INIT; // ev_flags设置为初始化
    ev->ev_ncalls = 0;          // 回调函数执行了0次
    ev->ev_pncalls = NULL;

    // 根据event的ev_events的值,设置event的关闭方式
    if (events & EV_SIGNAL) {...}
    else 
    {
        if (events & EV_PERSIST) { // event为
            evutil_timerclear(&ev->ev_io_timeout);  // 清除超时设置
            ev->ev_closure = EV_CLOSURE_PERSIST;
        } else {
            ev->ev_closure = EV_CLOSURE_NONE;
        }
    }

    ...
    // 优先级设置为active queue的大小的中间值
    ev->ev_pri = base->nactivequeues / 2;
    ...
    return (ev);
}

2 . 事件设置
对event的设置主要通过三个函数完成:event_set()、event_base_set()、event_priority_set()。

  • event_set函数的实现与event_new的类似,对event结构体的各参数进行赋值。
void event_set(struct event *ev,
                int fd, 
                short events, 
                void (*callback)(int, short, void *), // event的回调函数
                void *arg) // 用户传递的参数
  • event_base_set函数完成event注册到其他的event_base,仅当event的状态为EVLIST_INIT(即只执行了event_new,但还没有event_add)时,才能将event注册到新的event_base。
int event_base_set(struct event_base *base, struct event *ev)
  • event_priority_set函数设置event的执行优先级,仅当event的状态不是EVLIST_ACTIVE,才能将event的优先级进行设置。
int event_priority_set(struct event *ev, int pri)

本文参考:
Libevent源码分析—–超时event的处理
libevent源码深度剖析

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值