每日阅读3之内核设计与实现(第三版)4.5——linux调度实现之进程选择

在引入CFS调度思想的同时,我们希望能实现完美多任务处理器,以保证每个进程有相同的虚拟运行时间。

但现实中并不存在这样的多任务处理器,CFS使用一个很简单的规则来均衡所有进程的虚拟运行时间,即每次选择当前vruntime值最小的进程去执行。。

为实现这一点,CFS使用红黑树rbtree来组织可运行进程队列,所以实际上对于可运行进程调度的相关操作,实际上就是红黑树数据结构的一些基本操作的变形。。

(1)挑选下一个任务

实际上就是找红黑树最左端的节点,但一般在树的创建,变动过程中,内核都会缓存最左节点,以节省查找时间,提高系统性能。

实现这一过程的函数是,<kernel/sched_fairs.c>

static struct sched_entity *__pick_next_entity(struct cfs_rq *cfs_rq)
{
struct rb_node *left = cfs_rq->rb_leftmost;


if (!left)
return NULL;


return rb_entry(left, struct sched_entity, run_node);
}

(2)向树中加入进程

这一点发生在当进程变为可运行状态(被唤醒),或者通过fork()系统调用第一次创建一个进程,很显然这是一个rbtree的插入操作。。

static void __enqueue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se)
{
struct rb_node **link = &cfs_rq->tasks_timeline.rb_node;
struct rb_node *parent = NULL;
struct sched_entity *entry;
s64 key = entity_key(cfs_rq, se);
int leftmost = 1;


/*
* Find the right place in the rbtree:
*/
while (*link) {
parent = *link;
entry = rb_entry(parent, struct sched_entity, run_node);
/*
* We dont care about collisions. Nodes with
* the same key stay together.
*/
if (key < entity_key(cfs_rq, entry)) {
link = &parent->rb_left;
} else {
link = &parent->rb_right;
leftmost = 0;
}
}


/*
* Maintain a cache of leftmost tree entries (it is frequently
* used):
*/
if (leftmost)
cfs_rq->rb_leftmost = &se->run_node;


rb_link_node(&se->run_node, parent, link);
rb_insert_color(&se->run_node, &cfs_rq->tasks_timeline);
}

更新了很多统计数据,并最终调用rb_insert_color将其加入到红黑树中去,同时维护最左进程节点缓存并进行保持树平衡性的着色旋转。。


(3)从树中删除进程

发生在进程阻塞(变为不可运行态)或终止时(结束运行).

具体的实现在dequeue_entity(),__dequeue_entity()

大致的工作和插入差不多,维护最左缓存和维护树的平衡性。。


OVER!!!

下一节——调度器入口
























评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值