Linux内核初始化第8部分:调度器初始化详解

Linux内核初始化第8部分:调度器初始化详解

linux-insides-zh Linux 内核揭秘 linux-insides-zh 项目地址: 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(),主要完成以下工作:

  1. 获取当前CPU ID(引导处理器ID为0)
  2. 为当前CPU加载新的GDT(全局描述符表)
  3. 设置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()函数为每个节点建立分配顺序,确定当某个区域不能满足分配请求时应该尝试从哪些其他区域分配内存。

其他初始化工作

在调度器初始化前,内核还需要完成以下工作:

  1. 页面分配器初始化page_alloc_init()

    • 注册CPU热插拔通知器
    • 处理内存热插拔相关配置
  2. 命令行参数处理

    • parse_early_param():处理早期命令行参数
    • parse_args():处理非早期命令行参数
  3. 跳转标签初始化jump_label_init()

    • 初始化静态分支预测机制
  4. 日志缓冲区设置setup_log_buf()

    • 设置printk的日志缓冲区
  5. PID哈希表初始化pidhash_init()

    • 为进程ID建立哈希表,加速PID查找
    • 哈希表大小根据RAM配置决定,通常在2^4到2^12之间
  6. 内存管理初始化mm_init()

    • 初始化页面扩展数据
    • 释放启动内存
    • 初始化内核缓存
    • 初始化页表锁缓存
    • 初始化vmalloc

调度器初始化

终于来到核心部分——调度器初始化。sched_init()函数定义在kernel/sched/core.c中:

void __init sched_init(void)
{
    /* 调度器初始化代码 */
}

Linux调度器采用模块化设计,支持多种调度算法(称为调度类),主要包括:

  1. 完全公平调度器(CFS)

    • SCHED_NORMAL:普通进程调度策略
    • SCHED_BATCH:非交互式任务
    • SCHED_IDLE:空闲任务
  2. 实时调度器

    • 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_SCHEDCONFIG_RT_GROUP_SCHED选项允许对任务组进行调度,而不仅仅是单个任务。这使得系统管理员可以为不同的用户或应用组分配不同的CPU资源份额。

总结

本文详细分析了Linux内核初始化过程中调度器初始化的关键步骤。从SMP准备、内存区域划分到最终的调度器初始化,内核为多任务执行环境建立了坚实的基础架构。调度器的模块化设计使其能够灵活支持不同的调度策略,满足从实时系统到普通桌面环境的各种需求。

理解这些初始化过程对于深入掌握Linux内核工作原理至关重要,特别是在性能调优和系统资源管理方面。在后续文章中,我们将更详细地探讨Linux调度器的工作原理和实现细节。

linux-insides-zh Linux 内核揭秘 linux-insides-zh 项目地址: https://gitcode.com/gh_mirrors/lin/linux-insides-zh

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

骆宜鸣King

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值