Raspberry Pi OS 项目解析:深入理解任务调度器实现

Raspberry Pi OS 项目解析:深入理解任务调度器实现

raspberry-pi-os Learning operating system development using Linux kernel and Raspberry Pi raspberry-pi-os 项目地址: https://gitcode.com/gh_mirrors/ra/raspberry-pi-os

概述

在嵌入式系统开发中,任务调度是操作系统的核心功能之一。本文将深入分析Raspberry Pi OS中任务调度器的实现原理,帮助读者理解如何在裸机环境下构建一个简单的任务调度系统。

任务控制块(task_struct)

任何现代操作系统都需要一个数据结构来描述和管理任务(进程/线程)。Raspberry Pi OS借鉴了Linux的设计,使用task_struct结构体来保存任务信息:

struct cpu_context {
    unsigned long x19;
    unsigned long x20;
    // ... 其他寄存器
    unsigned long fp;  // 帧指针(x29)
    unsigned long sp;  // 栈指针
    unsigned long pc;  // 程序计数器(x30)
};

struct task_struct {
    struct cpu_context cpu_context;
    long state;
    long counter;
    long priority;
    long preempt_count;
};

关键字段解析

  1. cpu_context:保存任务执行上下文,仅包含x19-x30寄存器。根据ARM调用约定,x0-x18寄存器由被调用方负责保存,因此无需在上下文切换时保存。

  2. state:任务状态,当前仅实现TASK_RUNNING状态。

  3. counter:任务剩余时间片,每次时钟中断减1。

  4. priority:任务优先级,决定时间片大小。

  5. preempt_count:禁止抢占计数器,非零时表示任务正在执行关键代码。

内存管理

任务调度需要为每个任务分配独立的栈空间。RPi OS实现了一个简单的页式内存分配器:

unsigned long get_free_page() {
    for (int i = 0; i < PAGING_PAGES; i++){
        if (mem_map[i] == 0){
            mem_map[i] = 1;
            return LOW_MEMORY + i*PAGE_SIZE;
        }
    }
    return 0;
}

这个分配器具有以下特点:

  • 管理1GB-1MB的物理内存(最后1MB保留给设备)
  • 前4MB保留给内核和初始任务
  • 使用位图(mem_map)跟踪页面分配状态

任务创建

创建新任务的核心函数是copy_process

int copy_process(unsigned long fn, unsigned long arg) {
    // 分配task_struct和栈空间
    struct task_struct *p = (struct task_struct *)get_free_page();
    
    // 初始化任务属性
    p->priority = current->priority;
    p->state = TASK_RUNNING;
    p->counter = p->priority;
    p->preempt_count = 1;  // 初始禁止抢占
    
    // 设置执行上下文
    p->cpu_context.x19 = fn;      // 要执行的函数
    p->cpu_context.x20 = arg;     // 函数参数
    p->cpu_context.pc = (unsigned long)ret_from_fork;
    p->cpu_context.sp = (unsigned long)p + THREAD_SIZE;
    
    // 加入任务数组
    task[nr_tasks++] = p;
    return 0;
}

关键点:

  1. 新任务的栈空间与task_struct共享同一内存页
  2. pc寄存器指向ret_from_fork,这是任务的入口点
  3. 初始状态下禁止抢占,直到完成初始化

调度算法

RPi OS采用了Linux 0.01版本的调度算法,主要逻辑在_schedule函数中:

void _schedule(void) {
    while (1) {
        // 第一轮:寻找counter最大的就绪任务
        for (int i = 0; i < NR_TASKS; i++) {
            if (task[i] && task[i]->state == TASK_RUNNING && 
                task[i]->counter > c) {
                c = task[i]->counter;
                next = i;
            }
        }
        if (c) break;  // 找到合适任务
        
        // 第二轮:重新分配时间片
        for (int i = 0; i < NR_TASKS; i++) {
            if (task[i]) {
                task[i]->counter = (task[i]->counter >> 1) + task[i]->priority;
            }
        }
    }
    switch_to(task[next]);
}

算法特点:

  1. 优先选择counter值最大的就绪任务
  2. 若无合适任务,则重新计算所有任务的时间片
  3. 时间片计算公式保证:
    • 任务不会饿死
    • 时间片上限为2*priority

上下文切换

实际的任务切换由switch_to函数完成,它最终调用汇编函数cpu_switch_to

.globl cpu_switch_to
cpu_switch_to:
    mov    x10, #THREAD_CPU_CONTEXT
    add    x8, x0, x10
    mov    x9, sp
    stp    x19, x20, [x8], #16
    // 保存其他寄存器...
    str    x9, [x8]
    
    add    x8, x1, x10
    ldp    x19, x20, [x8], #16
    // 恢复其他寄存器...
    ldr    x9, [x8]
    mov    sp, x9
    ret

关键点:

  1. 仅保存/恢复被调用方保存的寄存器(x19-x30)
  2. 切换栈指针(sp)实现任务栈切换
  3. 通过ret指令跳转到新任务的pc寄存器值

调度触发机制

调度可能在两种情况下触发:

  1. 主动调度:任务调用schedule()自愿放弃CPU
  2. 被动调度:时钟中断处理程序调用timer_tick()
void timer_tick() {
    --current->counter;
    if (current->counter>0 || current->preempt_count >0) {
        return;
    }
    current->counter=0;
    enable_irq();  // 调度期间允许中断
    _schedule();
    disable_irq();
}

注意调度期间会临时启用中断,这是为了让等待中断的任务有机会被唤醒。

总结

Raspberry Pi OS实现了一个简单但完整的任务调度系统,具有以下特点:

  1. 支持多任务时间片轮转
  2. 采用优先级动态调整算法
  3. 实现基本的任务上下文保存/恢复
  4. 提供内存管理支持任务隔离

这个实现虽然简单,但包含了现代操作系统调度器的核心思想。读者可以通过扩展状态管理、增加调度策略等方式进一步完善这个系统。

raspberry-pi-os Learning operating system development using Linux kernel and Raspberry Pi raspberry-pi-os 项目地址: https://gitcode.com/gh_mirrors/ra/raspberry-pi-os

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

程季令

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

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

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

打赏作者

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

抵扣说明:

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

余额充值