Linux内核初始化第8部分:调度器初始化详解
linux-insides-zh Linux 内核揭秘 项目地址: https://gitcode.com/gh_mirrors/lin/linux-insides-zh
前言
在Linux内核初始化过程的第8部分中,我们将深入探讨调度器的初始化过程。作为操作系统核心组件之一,调度器负责决定哪个进程可以获得CPU资源以及何时获得。本文将详细分析Linux内核如何初始化其调度系统,包括相关数据结构的准备和调度策略的配置。
SMP准备工作
在进入调度器初始化之前,内核需要为SMP(对称多处理)系统做一些准备工作:
static inline void smp_prepare_boot_cpu(void)
{
smp_ops.smp_prepare_boot_cpu();
}
这个函数最终会调用native_smp_prepare_boot_cpu()
,主要完成以下工作:
- 获取当前CPU ID(引导处理器ID为0)
- 为当前CPU加载新的GDT(全局描述符表)
- 设置CPU状态为在线(CPU_ONLINE)
void __init native_smp_prepare_boot_cpu(void)
{
int me = smp_processor_id();
switch_to_new_gdt(me);
cpumask_set_cpu(me, cpu_callout_mask);
per_cpu(cpu_state, me) = CPU_ONLINE;
}
在多处理器系统中,Linux使用两个位图来管理处理器状态:
cpu_callout_mask
:表示哪些辅助处理器可以开始初始化cpu_callin_mask
:表示哪些辅助处理器已完成初始化
引导处理器初始化后,会更新cpu_callout_mask
来指示下一个可以初始化的辅助处理器。辅助处理器完成初始化后会设置自己在cpu_callin_mask
中的位。
内存区域初始化
接下来内核调用build_all_zonelists()
函数建立内存区域分配顺序:
void __init build_all_zonelists(void)
{
/* 建立所有节点的区域列表 */
}
Linux将物理内存划分为多个节点(node),每个节点又分为多个区域(zone):
ZONE_DMA
:0-16MB内存区域ZONE_DMA32
:32位设备DMA区域(低于4GB)ZONE_NORMAL
:x86_64上4GB以上的常规内存ZONE_HIGHMEM
:x86_64上不存在ZONE_MOVABLE
:包含可移动页面的区域
build_all_zonelists()
函数为每个节点建立分配顺序,确定当某个区域不能满足分配请求时应该尝试从哪些其他区域分配内存。
其他初始化工作
在调度器初始化前,内核还需要完成以下工作:
-
页面分配器初始化:
page_alloc_init()
- 注册CPU热插拔通知器
- 处理内存热插拔相关配置
-
命令行参数处理:
parse_early_param()
:处理早期命令行参数parse_args()
:处理非早期命令行参数
-
跳转标签初始化:
jump_label_init()
- 初始化静态分支预测机制
-
日志缓冲区设置:
setup_log_buf()
- 设置printk的日志缓冲区
-
PID哈希表初始化:
pidhash_init()
- 为进程ID建立哈希表,加速PID查找
- 哈希表大小根据RAM配置决定,通常在2^4到2^12之间
-
内存管理初始化:
mm_init()
- 初始化页面扩展数据
- 释放启动内存
- 初始化内核缓存
- 初始化页表锁缓存
- 初始化vmalloc
调度器初始化
终于来到核心部分——调度器初始化。sched_init()
函数定义在kernel/sched/core.c中:
void __init sched_init(void)
{
/* 调度器初始化代码 */
}
Linux调度器采用模块化设计,支持多种调度算法(称为调度类),主要包括:
-
完全公平调度器(CFS):
SCHED_NORMAL
:普通进程调度策略SCHED_BATCH
:非交互式任务SCHED_IDLE
:空闲任务
-
实时调度器:
SCHED_FIFO
:先进先出实时调度SCHED_RR
:轮转实时调度
调度器初始化时,会根据配置选项为不同的调度策略分配资源:
#ifdef CONFIG_FAIR_GROUP_SCHED
alloc_size += 2 * nr_cpu_ids * sizeof(void **);
#endif
#ifdef CONFIG_RT_GROUP_SCHED
alloc_size += 2 * nr_cpu_ids * sizeof(void **);
#endif
CONFIG_FAIR_GROUP_SCHED
和CONFIG_RT_GROUP_SCHED
选项允许对任务组进行调度,而不仅仅是单个任务。这使得系统管理员可以为不同的用户或应用组分配不同的CPU资源份额。
总结
本文详细分析了Linux内核初始化过程中调度器初始化的关键步骤。从SMP准备、内存区域划分到最终的调度器初始化,内核为多任务执行环境建立了坚实的基础架构。调度器的模块化设计使其能够灵活支持不同的调度策略,满足从实时系统到普通桌面环境的各种需求。
理解这些初始化过程对于深入掌握Linux内核工作原理至关重要,特别是在性能调优和系统资源管理方面。在后续文章中,我们将更详细地探讨Linux调度器的工作原理和实现细节。
linux-insides-zh Linux 内核揭秘 项目地址: https://gitcode.com/gh_mirrors/lin/linux-insides-zh
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考