libev源码解析——调度策略
在《libev源码解析——监视器(watcher)结构和组织形式》中介绍过,监视器分为[2,-2]区间5个等级的优先级。等级为2的监视器最高优,然后依次递减。不区分监视器类型和关联的文件描述符的值,权限高的要优先于权限低的执行。但是ANFD结构中的监视器链表无法满足高等级优先执行的特性。那么libev是如何解决这个问题的呢?(转载请指明出于breaksoftware的csdn博客)
anfds结构是以文件描述符作为索引的,其关心的是该描述符对应的事件是否发生。那我们关心不同等级执行顺序时,要以什么作为索引呢?那当然是等级值。libev也的确是这么做的
VAR (pendings, ANPENDING *pendings [NUMPRI])
VAR (pendingmax, int pendingmax [NUMPRI])
VAR (pendingcnt, int pendingcnt [NUMPRI])
NUMPRI是等级的个数,其定义是
#define NUMPRI (EV_MAXPRI - EV_MINPRI + 1)
pendings是一个具有5(2-(-2)+1))个元素的数组,不同等级和数组下标的对应关系通过下面这个宏来换算
# define ABSPRI(w) (((W)w)->priority - EV_MINPRI)
可见高等级的位于数组末尾,低等级的位于数组头部。即等级为2的pendings数组下标是4,而等级为-2的下标是0。
pendingmax记录的是每个等级已经记录的监视器个数。
pendingcnt记录的是每个等级中当前有效的监视器个数。这个值和ev_watcher中pending值有很大的相关性,之后我们会去将讨论。
pendings的每个元素是一个ANPENDING指针,其定义如下
typedef ev_watcher *W;
/* stores the pending event set for a given watcher */
typedef struct
{
W w;
int events; /* the pending event set for the given watcher */
} ANPENDING;
成员变量w是一个ev_watcher指针,它指向anfds中一个监视器。我们看到这个结构中没有指向自身的指针,如next、pre之类,那就说明ANPENDING是用数组结构保存的,而非动态链表。
那么anfds中的数据是如何转移到pendings上的呢?这个工作是由ev_feed_event函数完成
void noinline
ev_feed_event (EV_P_ void *w, int revents) EV_THROW
{
W w_ = (W)w;
int pri = ABSPRI (w_);
w是监视器变量指针,revents是发生了的事件。ABSPRI宏将监视器中的等级转换成pendings数组下标,从而确定该监视器属于哪个数组。
在一次循环前,每个监视器的pending位都将是0。因为对于没有触发的事件,其默认是0;而对于本次触发的事件,则在事件对应的回调函数被执行前,pending值被设置为0。该pending位的作用是用于记录该监视器信息在相应等级pendings数组的子数组中的位置。
假如这个事件在一次循环中被触发两次。则第一次它会走入else的逻辑,根据pendingcnt中相应等级找到其应该属于的pending位数。如果此时pandings空间不足,则需要使用array_needsize重新分配并填充该空间;第二次时,pending位已经确定,此时只要更新events字段即可。
if (expect_false (w_->pending))
pendings [pri][w_->pending - 1].events |= revents;
else
{
w_->pending = ++pendingcnt [pri];
array_needsize (ANPENDING, pendings [pri], pendingmax [pri], w_->pending, EMPTY2);
pendings [pri][w_->pending - 1].w = w_;
pendings [pri][w_->pending - 1].events = revents;
}
pendingpri = NUMPRI - 1;
}
pendings里保存的是事件已经被触发的监视器信息,这就包括回调已经被调用的和即将被调用的。对于回调已经被调用过的监视器,libev不会将其从数组中去掉,而只是简单的将其pending值设置为0。那么本次循环要遍历的ANPENDING元素个数可能比数组个数要少,其个数是pendingcnt数组中相应等级作为下标对应的值。
pendings中将数据准备好后,libev使用EV_INVOKE_PENDING宏遍历本次循环中更新的ANPENDING对象,调用其回调函数。
# define EV_INVOKE_PENDING ev_invoke_pending (EV_A)
void noinline
ev_invoke_pending (EV_P)
{
pendingpri = NUMPRI;
while (pendingpri) /* pendingpri possibly gets modified in the inner loop */
{
--pendingpri;
while (pendingcnt [pendingpri])
{
ANPENDING *p = pendings [pendingpri] + --pendingcnt [pendingpri];
p->w->pending = 0;
EV_CB_INVOKE (p->w, p->events);
EV_FREQUENT_CHECK;
}
}
}
#ifndef EV_CB_INVOKE
# define EV_CB_INVOKE(watcher,revents) (watcher)->cb (EV_A_ (watcher), (revents))
#endif
最后我们看下包括函数调用的结构图
- python实现Tab自动补全功能
- hdu-----(2807)The Shortest Path(矩阵+Floyd)
- hdu----(4686)Arc of Dream(矩阵快速幂)
- HDU----(4549)M斐波那契数列(小费马引理+快速矩阵幂)
- Centos系统修改时区
- zookeeper思考与总结1:在其它组件的作用及hdfs对比
- HDU----(4291)A Short problem(快速矩阵幂)
- Linux下删除指定文件之外的其他文件
- HDU----(2157)How many ways??(快速矩阵幂)
- 试试Linux下的ip命令
- hdu---(2604)Queuing(矩阵快速幂)
- centos7下卸载python后yum不能使用的恢复方法
- hdu---(5038)Grade(胡搞)
- shell生成随机字符的几种方法
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- ggplot Stripchart and line
- ggplot2 核密度图和直方图
- 喜欢的歌曲不在一个平台怎么办?你需要一个自己专属的音乐播放器
- ggplot_QQ图和ECDF
- tidyverse evaluation
- 下载歌曲的时候嫌麻烦?打造专属你的音乐下载器
- Tidyverse补充
- 抖音关键词热度搜索小程序(附源码)
- python自定义函数基础
- Python-科学计算-pandas-13-列名/删除列/替换nan
- python小程序,45行代码实现可切换版代码雨(附源码)
- R海拾遗-stringr
- stringr2
- Kubernetes 无状态应用的一般特征
- 一段简单的代码,能让所有GIF图实现时光倒流