libevent---事件event

一、libevent的核心-event

    Libevent是基于事件驱动(event-driven)的。event就是Reactor框架中的事件处理程序组件;它提供了函数接口,供Reactor在事件发生时调用,以执行相应的事件处理,通常它会绑定一个有效的句柄。

    首先给出event结构体的声明,它位于event.h文件中:

struct event {
	TAILQ_ENTRY (event) ev_next;
	TAILQ_ENTRY(event) ev_active_next;
	TAILQ_ENTRY (event) ev_signal_next;
	unsigned int min_heap_idx;	/* for managing timeouts */

	struct event_base *ev_base;

	int ev_fd;
	short ev_events;
	short ev_ncalls;
	short *ev_pncalls;	/* Allows deletes in callback */

	struct timeval ev_timeout;

	int ev_pri;		/* smaller numbers are higher priority */

	void (*ev_callback)(int, short, void *arg);
	void *ev_arg;

	int ev_res;		/* result passed to event callback */
	int ev_flags;
};

    下面详细解释一下结构体中各字段的含义。

    1)ev_next,ev_active_next和ev_signal_next都是双向链表节点指针;它们是libevent对不同事件类型和在不同的时期,对事件的管理时使用到的字段。libevent使用双向链表保存所有注册的I/O和Signal事件。

        ev_next就是该I/O事件在链表中的位置,称此链表为“已注册事件链表”;

        ev_signal_next就是signal事件在signal事件链表中的位置;

        ev_active_next:libevent将所有的激活事件放入到链表active list中,然后遍历active list执行调度,ev_active_next就指明了event在active list中的位置。(激活链表

        上述三个链表通过成员串连成一个尾队列。宏 TAILQ_ENTRY 是尾队列中的节点类型,它定义在compat/sys/queue.h中

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

    2)min_heap_idx和ev_timeout,如果是timeout事件,它们是event在小根堆中的索引和超时值,libevent使用小根堆来管理定时事件,这将在后面定时事件处理时专门讲解。

    3)ev_base该事件所属的反应堆实例,这是一个event_base结构体。

    4)ev_fd,对于I/O事件,是绑定的文件描述符;对于signal事件,是绑定的信号;对于定时器事件,赋值为-1。

    5)ev_events:event关注的事件类型,它可以是以下3种类型:
        I/O事件: EV_WRITE和EV_READ
        定时事件:EV_TIMEOUT
        信号: EV_SIGNAL
        辅助选项:EV_PERSIST,表明是一个永久事件

        Libevent中的定义为:

#define EV_TIMEOUT	0x01
#define EV_READ		0x02
#define EV_WRITE	0x04
#define EV_SIGNAL	0x08
#define EV_PERSIST	0x10	/* Persistant event */

        可以看出事件类型可以使用“|”运算符进行组合,需要说明的是,信号和I/O事件不能同时设置。还可以看出libevent使用event结构体将这3种事件的处理统一起来。

    6)ev_callback,event的回调函数,被ev_base调用,执行事件处理程序,这是一个函数指针,原型为:

void (*ev_callback)(int fd, short events, void *arg);

        其中参数fd对应于ev_fd;events对应于ev_events;arg对应于ev_arg。

    7)ev_arg:void*,表明可以是任意类型的数据,在设置event时指定。

    8)eb_flags:libevent用于标记event信息的字段,表明其当前的状态,可能的值有:

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

/* EVLIST_X_ Private space: 0x1000-0xf000 */
#define EVLIST_ALL	(0xf000 | 0x9f)

    9)ev_ncalls:事件就绪执行时,调用ev_callback的次数,通常为1。

    10)ev_pncalls:指针,通常指向ev_ncalls或者为NULL。

    11)ev_res:记录了当前激活事件的类型。


二、libevent 对event的管理

    从event结构体中的3个链表节点指针和一个堆索引出发,可以参见下面的示意图。

    每次当有事件event转变为就绪状态时,libevent就会把它移入到active event list[priority]中,其中priority是event的优先级;接着libevent会根据自己的调度策略选择就绪事件,调用其cb_callback()函数执行事件处理;并根据就绪的句柄和事件类型填充cb_callback函数的参数。



三、事件设置的接口函数

    要向libevent添加一个事件,需要首先设置event对象,这通过调用libevent提供的函数有:event_set(), event_base_set(), event_priority_set()来完成;下面分别进行讲解。

    1)event_set()

void event_set(struct event *ev, int fd, short events,
	  void (*callback)(int, short, void *), void *arg)
{
	/* Take the current base - caller needs to set the real base later */
	ev->ev_base = current_base;//此处current_base=NULL,所以设置的event所属的ev_base也为NULL,待下一函数event_bae_set设置en->en_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;

	min_heap_elem_init(ev);

	/* by default, we put new events into the middle priority */
	if(current_base)
		ev->ev_pri = current_base->nactivequeues/2;
}
        1.设置事件 ev 绑定的文件描述符或者信号,对于定时事件,设为-1即可;
        2.设置事件类型,比如EV_READ|EV_PERSIST, EV_WRITE, EV_SIGNAL等;
        3.设置事件的回调函数以及参数arg;

        4.初始化其它字段,比如缺省的event_base和优先级;

        注意:此时

    2)event_base_set()

int event_base_set(struct event_base *base, struct event *ev)
{
	/* Only innocent events may be assigned to a different base */
	if (ev->ev_flags != EVLIST_INIT)
		return (-1);

	ev->ev_base = base;
	ev->ev_pri = base->nactivequeues/2;

	return (0);
}

        设置event ev将要注册到的event_base;

        libevent有一个全局event_base指针current_base,默认情况下事件ev将被注册到current_base上,使用该函数可以指定不同的event_base;如果一个进程中存在多个libevent实例,则必须要调用该函数为event设置不同的event_base。

    3)event_priority_set()

int event_priority_set(struct event *ev, int pri)
{
	if (ev->ev_flags & EVLIST_ACTIVE)
		return (-1);
	if (pri < 0 || pri >= ev->ev_base->nactivequeues)
		return (-1);

	ev->ev_pri = pri;

	return (0);
}
    当ev正处于就绪状态时,不能设置,返回-1。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值