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是怎么插入到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_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是怎么插入到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;//默认优先级
- }
- ...
- }