/* file: kernel/sched/fair.c */
static void update_curr(struct cfs_rq *cfs_rq) {
struct sched_entity *curr = cfs_rq->curr;
u64 now = rq_clock_task(rq_of(cfs_rq));
u64 delta_exec;
/* 本次更新 vruntime 与上次更新 vruntime 之间的差值 */
delta_exec = now - curr->exec_start;
/* 省略其他更新时间的代码,这部分在讨论vruntime时已经讨论过 */
/* 更新与带宽控制相关的字段 */
account_cfs_rq_runtime(cfs_rq, delta_exec);
}
/* 判断是否启用了带宽控制,如果是的话调用函数__account_cfs_rq_runtime更新对应字段
*/
static __always_inline void account_cfs_rq_runtime(struct cfs_rq *cfs_rq,
u64 delta_exec) {
if (!cfs_bandwidth_used() || !cfs_rq->runtime_enabled)
return;
__account_cfs_rq_runtime(cfs_rq, delta_exec);
}
static void __account_cfs_rq_runtime(struct cfs_rq *cfs_rq, u64 delta_exec) {
/* 从剩余时间中减去这次消耗掉的部分,注意这里可能导致cfs_rq->runtime_remaining为负数
*/
cfs_rq->runtime_remaining -= delta_exec;
/* 如果还有剩余时间,则函数返回 */
if (likely(cfs_rq->runtime_remaining > 0))
return;
/* 接下来要向所在的任务组申请时间,但如果当前cfs_rq已经被挂起了的话,就不用麻烦了
*/
if (cfs_rq->throttled)
return;
/*
* 此时我们调用函数assign_cfs_rq_runtime向任务组申请时间。如果申请时间失败,则cfs_rq应该被挂起。
* 这里调用resched_curr标记cfs_rq->curr的TIF_NEED_RESCHED位,以便随后将其调度出去
*/
if (!assign_cfs_rq_runtime(cfs_rq) && likely(cfs_rq->curr))
resched_curr(rq_of(cfs_rq));
}
/* file: kernel/sched/fair.c */
static int assign_cfs_rq_runtime(struct cfs_rq *cfs_rq) {
/* 返回task_group的cfs_bandwidth字段,该字段封装着整个任务组的带宽数据 */
struct cfs_bandwidth *cfs_b = tg_cfs_bandwidth(cfs_rq->tg);
int ret;
raw_spin_lock(&cfs_b->lock);
/* 实际的申请逻辑,第三个参数是期望申请的时间额度,默认是5ms */
ret = __assign_cfs_rq_runtime(cfs_b, cfs_rq, sched_cfs_bandwidth_slice());
raw_spin_unlock(&cfs_b->lock);
return ret;
}
static int __assign_cfs_rq_runtime(struct cfs_bandwidth *cfs_b,
struct cfs_rq *cfs_rq, u64 target_runtime) {
u64 min_amount, amount = 0;
lockdep_assert_held(&cfs_b->lock);
/* 前文聊到更新带宽时间时,提到 cfs_rq->runtime_remaining
* 可能为负,这说明上次运行时已经透支了部分时间,这里补回来。
*/
min_amount = target_runtime - cfs_rq->runtime_remaining;
/* 没有限制,则要多少分配多少 */
if (cfs_b->quota == RUNTIME_INF)
amount = min_amount;
else {
/* 保证定时器是打开的,保证周期性地为任务组重置带宽时间 */
start_cfs_bandwidth(cfs_b);
/* 如果本周期内还有时间,则可以分配 */
if (cfs_b->runtime > 0) {
/* 确保不要透支 */
amount = min(cfs_b->runtime, min_amount);
cfs_b->runtime -= amount;
cfs_b->idle = 0;
}
}
/* 将新申请到的时间补充给cfs_rq */
cfs_rq->runtime_remaining += amount;
/* 是否成功地从task_group中申请到了时间 */
return cfs_rq->runtime_remaining > 0;
}