Linux核心概念详解
  • 0. Linux核心概念详解
  • 1. 调试环境
  • 2. Linux 调度器
    • 2.1 任务
    • 2.2 核心概念
      • 2.2.1 核心概念 - 调度实体
      • 2.2.2 核心概念 - 调度类
      • 2.2.3 核心概念 - 调度策略
      • 2.2.4 核心概念 - 运行队列
      • 2.2.5 核心概念 - 优先级
    • 2.3 演进历史
      • 2.3.1 O(n)调度器 - 调度逻辑
      • 2.3.2 O(n)调度器 - 时间分配
      • 2.3.3 O(n)调度器 - 调度时机
      • 2.3.4 O(1)调度器 - 简介
      • 2.3.5 O(1)调度器 - 调度逻辑
      • 2.3.6 O(1)调度器 - 时间分配
      • 2.3.7 RSDL
      • 2.3.8 CFS
    • 2.4 DL调度器
      • 2.4.1 DL调度器 - 调度算法
      • 2.4.2 DL调度器 -核心代码
    • 2.5 RT调度器
    • 2.6 CFS
      • 2.6.1 公平性
      • 2.6.2 调度逻辑
      • 2.6.2.1 调度逻辑 - 数据结构
      • 2.6.2.2 调度逻辑 - vruntime
      • 2.6.2.3 调度逻辑 - 调度周期
      • 2.6.2.4 调度逻辑 - 调度节拍
      • 2.6.2.5 调度逻辑 - 任务抢占
      • 2.6.2.6 调度逻辑 - 调度时机
      • 2.6.3 组调度
      • 2.6.3.1 组调度 - 数据结构
      • 2.6.3.2 组调度 - 调度逻辑
      • 2.6.3.3 组调度 - 时间分配
      • 2.6.3.4 组调度 - 任务组权重
      • 2.6.4 带宽控制
      • 2.6.4.1 带宽控制 - 数据结构
      • 2.6.4.2 带宽控制 - 带宽时间
      • 2.6.4.3 带宽控制 - 挂起与解挂
      • 2.6.4.3 带宽控制 - 定时器
    • 2.7 负载追踪
      • 2.7.1 负载追踪 - 简介
      • 2.7.2 负载追踪 - 数据结构
      • 2.7.3 负载追踪 - 计算负载
      • 2.7.4 负载追踪 - 更新负载
    • 2.8 负载均衡
      • 2.8.1 简介
      • 2.8.2 CPU的拓扑结构
      • 2.8.3 数据结构
      • 2.8.4 算法思路
      • 2.8.5 触发时机
      • 2.8.6 总结
  • 3. LINUX 内存管理
    • 3.1 寻址模式
      • 3.1.1 地址
      • 3.1.2 地址转换
      • 3.1.3 Linux的地址空间
    • 3.2 物理内存
      • 3.2.1 数据结构
      • 3.2.2 初始化
      • 3.2.3 物理内存模型
      • 3.2.4 Buddy System(伙伴系统)
      • 3.2.5 SLAB/SLUB/SLOB
Powered by GitBook
On this page

Was this helpful?

  1. 2. Linux 调度器
  2. 2.6 CFS

2.6.2.4 调度逻辑 - 调度节拍

计算机系统随着时钟节拍需要周期性地做很多事情,例如刷新屏幕、数据落盘等,而进程调度是众多任务中最重要的之一。周期性调度也叫调度节拍,它的入口是函数 schedule_tick(), 该函数最终会调用调度类的 task_tick() 方法完成操作:

/* file: kernel/sched/core.c */
void scheduler_tick(void) {
int cpu = smp_processor_id();
struct rq *rq = cpu_rq(cpu);
struct task_struct *curr = rq->curr;

/* 调用当前任务的调度类的 task_tick 方法 */
curr->sched_class->task_tick(rq, curr, 0);

#ifdef CONFIG_SMP
/* SMP 架构下触发负载均衡 */
rq->idle_balance = idle_cpu(cpu);
trigger_load_balance(rq);
#endif
}

CFS 中实现 task_tick 方法的是函数 task_tick_fair:

/* file: kernel/sched/fair.c */
static void task_tick_fair(struct rq *rq, struct task_struct *curr,
                    int queued) {
struct cfs_rq *cfs_rq;
struct sched_entity *se = &curr->se;

/* 在不考虑组调度的情况下,此处的循环只会迭代一次,处理的就是当前任务 */
for_each_sched_entity(se) {
cfs_rq = cfs_rq_of(se);
entity_tick(cfs_rq, se, queued);
}
}

实际的逻辑都在函数 entity_tick 中,删除无关代码及与组调度相关的逻辑,主要逻辑如下:

/* file: kernel/sched/fair.c */
static void entity_tick(struct cfs_rq *cfs_rq, struct sched_entity *curr,
                int queued)
{
/* 首先更新当前任务及队列的各种时间信息,详见 vruntime 一节 */
update_curr(cfs_rq);

if (cfs_rq->nr_running > 1)
/* 检查是否需要抢占当前任务 */
check_preempt_tick(cfs_rq, curr);
}

该函数的主要任务有两个,一个是更新任务的各种时间信息;另一个是检查当前任务是否已经执行地足够久了,如果是的话就需要对其进行抢占,换其它任务来执行。关于抢占的概念将在下一节中介绍。

Previous2.6.2.3 调度逻辑 - 调度周期Next2.6.2.5 调度逻辑 - 任务抢占

Last updated 3 years ago

Was this helpful?