Libevent源码分析-----event优先级设置

        转载请注明出处: http://blog.csdn.net/luotuo44/article/details/38512719



        event_base允许用户对它里面的event设置优先级,这样可以使得有些更重要的event能够得到优先处理。

        Libevent实现优先级功能的方法是:用一个激活队列数组来存放激活event。即数组的元素是一个激活队列,所以有多个激活队列。并且规定不同的队列有不同的优先级。


        可以通过event_base_priority_init函数设置event_base的优先级个数,该函数实现如下:

//event.c文件 
int
event_base_priority_init(struct event_base *base, int npriorities)
{
	int i;

	//由N_ACTIVE_CALLBACKS宏可以知道,本函数应该要在event_base_dispatch
	//函数调用前调用。不然将无法设置。
	if (N_ACTIVE_CALLBACKS(base) || npriorities < 1
	    || npriorities >= EVENT_MAX_PRIORITIES)
		return (-1);

	//之前和现在要设置的优先级数是一样的。
	if (npriorities == base->nactivequeues)
		return (0);

	//释放之前的,因为N_ACTIVE_CALLBACKS,所以没有active的event。
	//可以随便mm_free
	if (base->nactivequeues) { 
		mm_free(base->activequeues);
		base->nactivequeues = 0;
	}

	//分配一个优先级数组。
	base->activequeues = (struct event_list *)
	  mm_calloc(npriorities, sizeof(struct event_list));
	if (base->activequeues == NULL) {
		event_warn("%s: calloc", __func__);
		return (-1);
	}
	base->nactivequeues = npriorities;

	for (i = 0; i < base->nactivequeues; ++i) {
		TAILQ_INIT(&base->activequeues[i]);
	}

	return (0);
}

        从前面一个判断可知,因为event_base_dispatch函数会改动激活事件的个数,即会使得N_ACTIVE_CALLBACKS(base)为真。所以event_base_priority_init函数要在event_base_dispatch函数之前调用。此外要设置的优先级个数,要小于EVENT_MAX_PRIORITIES。这个宏是在event.h文件中定义,在2.0.21版本中,该宏被定义成256。在调用event_base_new得到的event_base只有一个优先级,也就是所有event都是同级的。

        上面的代码调用mm_alloc分配了一个优先级数组。不同优先级的event会被放到数组的不同位置上(下面可以看到这一点)。这样就可以区分不同event的优先级了。以后处理event时,就可以从高优先级到低优先级处理event。

 

 

        上面是设置event_base的优先级个数。现在来看一下怎么设置event的优先级。可以通过event_priority_set函数设置,该函数如下:
//event.c文件
int
event_priority_set(struct event *ev, int pri)
{
	_event_debug_assert_is_setup(ev);

	if (ev->ev_flags & EVLIST_ACTIVE)
		return (-1);
	
//优先级不能越界
	if (pri < 0 || pri >= ev->ev_base->nactivequeues)
		return (-1);

	//pri值越小,其优先级就越高。
	ev->ev_pri = pri;

	return (0);
}
        在上面代码的第一个判断中,可以知道当event的状态是EVLIST_ACTIVE时,就不能对这个event进行优先级设置了。因此,如果要对event进行优先级设置,那么得在调用event_base_dispatch函数之前。因为一旦调用了event_base_dispatch,那么event就随时可能变成EVLIST_ACTIVE状态。


        现在看一下一个event是怎么插入到event_base的优先级数组中。

//event.c文件
//event_active_nolock以event_queue_insert(base, ev, EVLIST_ACTIVE);方式调用
static void
event_queue_insert(struct event_base *base, struct event *ev, int queue)
{
	....

	ev->ev_flags |= queue; //加入EVLIST_ACTIVE状态
	switch (queue) {
	...
	case EVLIST_ACTIVE:
		base->event_count_active++;
		//从优先级数组中找到对应的优先级
		TAILQ_INSERT_TAIL(&base->activequeues[ev->ev_pri],
		    ev,ev_active_next);
		break;
	...
	}
}


        最后,我们来看一下默认的event优先级是多少。想必大家都能想到这个默认优先级是在新建event结构体时设置的。不错,看下面的event_assign函数。

//event.c文件  由event_new函数调用本函数
int
event_assign(struct event *ev, struct event_base *base, evutil_socket_t fd, 
			      short events, void (*callback)(evutil_socket_t, short, void *), void *arg)
{
	...

	ev->ev_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;

    ....

	if (base != NULL) {
		/* by default, we put new events into the middle priority */
		ev->ev_pri = base->nactivequeues / 2;//默认优先级
	}

	...
}
        在这个函数里面,对event的成员变量进行了一些设置。其中,优先级的设置值为优先级数组长度的一半,所以是中间优先级。




你可能感兴趣的:(libevent)