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



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

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


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

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. //event.c文件   
  2. int  
  3. event_base_priority_init(struct event_base *base, int npriorities)  
  4. {  
  5.     int i;  
  6.   
  7.     //由N_ACTIVE_CALLBACKS宏可以知道,本函数应该要在event_base_dispatch  
  8.     //函数调用前调用。不然将无法设置。  
  9.     if (N_ACTIVE_CALLBACKS(base) || npriorities < 1  
  10.         || npriorities >= EVENT_MAX_PRIORITIES)  
  11.         return (-1);  
  12.   
  13.     //之前和现在要设置的优先级数是一样的。  
  14.     if (npriorities == base->nactivequeues)  
  15.         return (0);  
  16.   
  17.     //释放之前的,因为N_ACTIVE_CALLBACKS,所以没有active的event。  
  18.     //可以随便mm_free  
  19.     if (base->nactivequeues) {   
  20.         mm_free(base->activequeues);  
  21.         base->nactivequeues = 0;  
  22.     }  
  23.   
  24.     //分配一个优先级数组。  
  25.     base->activequeues = (struct event_list *)  
  26.       mm_calloc(npriorities, sizeof(struct event_list));  
  27.     if (base->activequeues == NULL) {  
  28.         event_warn("%s: calloc", __func__);  
  29.         return (-1);  
  30.     }  
  31.     base->nactivequeues = npriorities;  
  32.   
  33.     for (i = 0; i < base->nactivequeues; ++i) {  
  34.         TAILQ_INIT(&base->activequeues[i]);  
  35.     }  
  36.   
  37.     return (0);  
  38. }  

        从前面一个判断可知,因为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函数设置,该函数如下:
[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. //event.c文件  
  2. int  
  3. event_priority_set(struct event *ev, int pri)  
  4. {  
  5.     _event_debug_assert_is_setup(ev);  
  6.   
  7.     if (ev->ev_flags & EVLIST_ACTIVE)  
  8.         return (-1);  
  9.       
  10. //优先级不能越界  
  11.     if (pri < 0 || pri >= ev->ev_base->nactivequeues)  
  12.         return (-1);  
  13.   
  14.     //pri值越小,其优先级就越高。  
  15.     ev->ev_pri = pri;  
  16.   
  17.     return (0);  
  18. }  
        在上面代码的第一个判断中,可以知道当event的状态是EVLIST_ACTIVE时,就不能对这个event进行优先级设置了。因此,如果要对event进行优先级设置,那么得在调用event_base_dispatch函数之前。因为一旦调用了event_base_dispatch,那么event就随时可能变成EVLIST_ACTIVE状态。


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

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. //event.c文件  
  2. //event_active_nolock以event_queue_insert(base, ev, EVLIST_ACTIVE);方式调用  
  3. static void  
  4. event_queue_insert(struct event_base *base, struct event *ev, int queue)  
  5. {  
  6.     ....  
  7.   
  8.     ev->ev_flags |= queue; //加入EVLIST_ACTIVE状态  
  9.     switch (queue) {  
  10.     ...  
  11.     case EVLIST_ACTIVE:  
  12.         base->event_count_active++;  
  13.         //从优先级数组中找到对应的优先级  
  14.         TAILQ_INSERT_TAIL(&base->activequeues[ev->ev_pri],  
  15.             ev,ev_active_next);  
  16.         break;  
  17.     ...  
  18.     }  
  19. }  


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

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. //event.c文件  由event_new函数调用本函数  
  2. int  
  3. event_assign(struct event *ev, struct event_base *base, evutil_socket_t fd,   
  4.                   short events, void (*callback)(evutil_socket_t, shortvoid *), void *arg)  
  5. {  
  6.     ...  
  7.   
  8.     ev->ev_base = base;  
  9.     ev->ev_callback = callback;  
  10.     ev->ev_arg = arg;  
  11.     ev->ev_fd = fd;  
  12.     ev->ev_events = events;  
  13.     ev->ev_res = 0;  
  14.     ev->ev_flags = EVLIST_INIT;  
  15.     ev->ev_ncalls = 0;  
  16.     ev->ev_pncalls = NULL;  
  17.   
  18.     ....  
  19.   
  20.     if (base != NULL) {  
  21.         /* by default, we put new events into the middle priority */  
  22.         ev->ev_pri = base->nactivequeues / 2;//默认优先级  
  23.     }  
  24.   
  25.     ...  
  26. }  
        在这个函数里面,对event的成员变量进行了一些设置。其中,优先级的设置值为优先级数组长度的一半,所以是中间优先级。
        event_base允许用户对它里面的event设置优先级,这样可以使得有些更重要的event能够得到优先处理。

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


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

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. //event.c文件   
  2. int  
  3. event_base_priority_init(struct event_base *base, int npriorities)  
  4. {  
  5.     int i;  
  6.   
  7.     //由N_ACTIVE_CALLBACKS宏可以知道,本函数应该要在event_base_dispatch  
  8.     //函数调用前调用。不然将无法设置。  
  9.     if (N_ACTIVE_CALLBACKS(base) || npriorities < 1  
  10.         || npriorities >= EVENT_MAX_PRIORITIES)  
  11.         return (-1);  
  12.   
  13.     //之前和现在要设置的优先级数是一样的。  
  14.     if (npriorities == base->nactivequeues)  
  15.         return (0);  
  16.   
  17.     //释放之前的,因为N_ACTIVE_CALLBACKS,所以没有active的event。  
  18.     //可以随便mm_free  
  19.     if (base->nactivequeues) {   
  20.         mm_free(base->activequeues);  
  21.         base->nactivequeues = 0;  
  22.     }  
  23.   
  24.     //分配一个优先级数组。  
  25.     base->activequeues = (struct event_list *)  
  26.       mm_calloc(npriorities, sizeof(struct event_list));  
  27.     if (base->activequeues == NULL) {  
  28.         event_warn("%s: calloc", __func__);  
  29.         return (-1);  
  30.     }  
  31.     base->nactivequeues = npriorities;  
  32.   
  33.     for (i = 0; i < base->nactivequeues; ++i) {  
  34.         TAILQ_INIT(&base->activequeues[i]);  
  35.     }  
  36.   
  37.     return (0);  
  38. }  

        从前面一个判断可知,因为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函数设置,该函数如下:
[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. //event.c文件  
  2. int  
  3. event_priority_set(struct event *ev, int pri)  
  4. {  
  5.     _event_debug_assert_is_setup(ev);  
  6.   
  7.     if (ev->ev_flags & EVLIST_ACTIVE)  
  8.         return (-1);  
  9.       
  10. //优先级不能越界  
  11.     if (pri < 0 || pri >= ev->ev_base->nactivequeues)  
  12.         return (-1);  
  13.   
  14.     //pri值越小,其优先级就越高。  
  15.     ev->ev_pri = pri;  
  16.   
  17.     return (0);  
  18. }  
        在上面代码的第一个判断中,可以知道当event的状态是EVLIST_ACTIVE时,就不能对这个event进行优先级设置了。因此,如果要对event进行优先级设置,那么得在调用event_base_dispatch函数之前。因为一旦调用了event_base_dispatch,那么event就随时可能变成EVLIST_ACTIVE状态。


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

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. //event.c文件  
  2. //event_active_nolock以event_queue_insert(base, ev, EVLIST_ACTIVE);方式调用  
  3. static void  
  4. event_queue_insert(struct event_base *base, struct event *ev, int queue)  
  5. {  
  6.     ....  
  7.   
  8.     ev->ev_flags |= queue; //加入EVLIST_ACTIVE状态  
  9.     switch (queue) {  
  10.     ...  
  11.     case EVLIST_ACTIVE:  
  12.         base->event_count_active++;  
  13.         //从优先级数组中找到对应的优先级  
  14.         TAILQ_INSERT_TAIL(&base->activequeues[ev->ev_pri],  
  15.             ev,ev_active_next);  
  16.         break;  
  17.     ...  
  18.     }  
  19. }  


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

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. //event.c文件  由event_new函数调用本函数  
  2. int  
  3. event_assign(struct event *ev, struct event_base *base, evutil_socket_t fd,   
  4.                   short events, void (*callback)(evutil_socket_t, shortvoid *), void *arg)  
  5. {  
  6.     ...  
  7.   
  8.     ev->ev_base = base;  
  9.     ev->ev_callback = callback;  
  10.     ev->ev_arg = arg;  
  11.     ev->ev_fd = fd;  
  12.     ev->ev_events = events;  
  13.     ev->ev_res = 0;  
  14.     ev->ev_flags = EVLIST_INIT;  
  15.     ev->ev_ncalls = 0;  
  16.     ev->ev_pncalls = NULL;  
  17.   
  18.     ....  
  19.   
  20.     if (base != NULL) {  
  21.         /* by default, we put new events into the middle priority */  
  22.         ev->ev_pri = base->nactivequeues / 2;//默认优先级  
  23.     }  
  24.   
  25.     ...  
  26. }  
        在这个函数里面,对event的成员变量进行了一些设置。其中,优先级的设置值为优先级数组长度的一半,所以是中间优先级。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值