libevent主要数据结构

通用结构体

#define TAILQ_ENTRY(type)            \
struct {                                \
    struct type *tqe_next;  /* next element */       \
    struct type **tqe_prev; /* previous element */  \
}
放置在event结构体中,将event串成队列。

#define TAILQ_HEAD(name, type)           \
struct name {                               \
    struct type *tqh_first; /* 队列头*/      \
    struct type **tqh_last; /* 队列尾 */     \
}

event_base

event_base 代表一个libevent实体。其结构如下:

struct event_base {
    const struct eventop *evsel;  /* evbase对应的操作函数 */
    void *evbase;                 /* 采用何种IO多路复用函数 */
    
    int event_count;         /* 事件总量 */
    int event_count_active;  /* 激活事件数量 */

    int event_gotterm;      /* 优雅的结束,处理完激活事件队列中事件后结束 */
    int event_break;        /* 立即结束 */

    
    struct event_list **activequeues; /* 多个激活事件队列 */
    int nactivequeues;                /* 队列个数,0最高优先级 */

    struct evsignal_info sig;         /* 信号结构体 */
    struct event_list eventqueue;     /* 信号/IO事件队列 */
    struct min_heap timeheap;         /* 时间堆 */

    struct timeval tv_cache;          /* 缓存时间 */
    struct timeval event_tv;          /* 事件时间 */
};
1.  evsel 与 evbase

 evsel 代表操作集合。

const struct eventop epollops = {
	"epoll",
	epoll_init,
	epoll_add,
	epoll_del,
	epoll_dispatch,
	epoll_dealloc,
	1 /* need reinit */
};
evbase 代表采用哪种IO多路复用函数, epoll, select, poll等。
struct epollop {
	struct evepoll *fds;
	int nfds;
	
	struct epoll_event *events;
	int nevents;
	
	int epfd;
};
上述两者配对使用,evbase 相当于C++的this指针,而epollops内的函数相当于类的成员函数。


2. activequeues

    activequeues队列是一个指针数组,数组中每个元素可以指向一个事件队列;数组索引表示优先级,0代表最高优先级。

当处理事件时候,从头扫描数组,若发现非空事件队列,进行处理,只有当前优先级队列处理完成后,才进行下一优先级的处理。


3. sig、eventqueue、timeheap

    上述三个变量分别用于处理信号事件,信号与IO事件队列,定时器事件小根堆。


4. tv_cache 、 event_tv

    由于获取时间需要调用系统调用,这是一个耗时操作,因此libevent将时间缓存,减少系统调用次数,从而达到加速的目的。

event_tv 用于修正时间,后续时间管理章节说明。


event

struct event {
    TAILQ_ENTRY (event) ev_next;        /* IO、信号事件结点 */
    TAILQ_ENTRY (event) ev_active_next; /* 激活事件结点 */
    TAILQ_ENTRY (event) ev_signal_next; /* 信号事件结点 */
    unsigned int min_heap_idx;          /* 时间堆中索引位置 */

    struct event_base *ev_base;         /* 指向event_base 结构体 */

    int ev_fd;             /* 用户套接字 或 信号*/
    short ev_events;       /* 事件类型,可读,可写,持久,超时 */
    short ev_ncalls;       /* 事件回调函数需要被调用次数 */
    short *ev_pncalls;     /* Allows deletes in callback */

    struct timeval ev_timeout; /* 超时时刻 */

    int ev_pri;                /* 事件优先级,0最高优先级 */

    void (*ev_callback)(int, short, void *arg);/* 事件回调函数 */
    void *ev_arg; /* 回调函数参数 */

    int ev_res;     /* result passed to event callback */
    int ev_flags;   /* 事件目前状态, TIMEOUT, INIT, SIGNAL */
};

1. ev_next、ev_active_next、ev_singal_next、min_head_idx

    上述四个变量比较易于理解,分别是事件在不同队列中的一个节点。有一个奇怪点,信号事件既在ev_next中,

又在ev_signal_next中。当用户添加信号事件的时候,会在事件队列中添加,同时,也会在该信号对应的队列中添加。

允许同一信号,注册不同的事件,这样signal[sig no] 将会挂一个链表,如下图。详细内容在信号一节中说明。

j

(图片来自互联网)

2. ev_events

#define EV_TIMEOUT	0x01
#define EV_READ		0x02
#define EV_WRITE	0x04
#define EV_SIGNAL	0x08
#define EV_PERSIST	0x10	/* Persistant event */
在添加事件的时候指定事件类型,如果非持久事件,则事件在处理后被删除。

3. ev_flags

#define EVLIST_TIMEOUT	0x01
#define EVLIST_INSERTED	0x02
#define EVLIST_SIGNAL	0x04
#define EVLIST_ACTIVE	0x08
#define EVLIST_INTERNAL	0x10
#define EVLIST_INIT	0x80
当前事件在内部的状态,是否已经超时,是否已经插入事件队列等等。

4. ev_ncalls

    运行一个事件的回调函数被调用ev_ncalls次, 主要是用来记录信号,即同一事件对应的信号在一定时间内发生了n次,

则调用该事件回调函数n次。


5. ev_timeout

    如果该事件为一个超时事件,那么ev_timeout记录该事件超时的时间点。比如当前时间是1:40, 那么用户指定10分钟后超时,

则ev_timeout为1:50.


6. ev_res

    该参数传递给用户注册的事件回调函数,告诉用户,该事件是由于响应了什么事件而被激活的。例如:

if (evread != NULL)
    event_active(evread, EV_READ, 1);
在epoll中,若一个事件可读,通过event_active将事件加入激活队列中去,此时, EV_READ表示该事件激活是由于可读。

可见ev_res的取值内容同ev_events一致。

void
event_active(struct event *ev, int res, short ncalls)
{
	ev->ev_res = res;
	event_queue_insert(ev->ev_base, ev, EVLIST_ACTIVE);
}
当处理该事件的时候,ev_res传递给用户回调函数。

while (ncalls) {
    ncalls--;
    ev->ev_ncalls = ncalls;
    (*ev->ev_callback)((int)ev->ev_fd, ev->ev_res, ev->ev_arg);
    if (base->event_break)
        return;
}
插一句:上述可以看到如果event_break为真,立即返回,即使激活事件队列中还有激活事件,也不在进行处理了。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值