任务调度 - 常见错误
错误 1:上下文切换后崩溃
症状
第一次上下文切换后系统立即崩溃。
原因
新进程栈上的初始上下文与switch_context中pop的顺序不匹配。
解决方案
确保process_create中的栈初始化与switch.asm中的pop顺序完全对应:
switch.asm: pop edi, pop esi, pop ebx, pop ebp, ret
→ 栈上需要: EDI, ESI, EBX, EBP, 返回地址(entry)
错误 2:定时器中断不触发
症状
注册了timer_handler但从未被调用。
原因
- PIT配置错误(频率/端口/命令字节)
- 中断处理器注册在错误的向量号
- 中断被关闭(没有sti)
解决方案
// 确认注册在向量32(IRQ0重映射后)
register_interrupt_handler(32, timer_handler);
// 确认PIT配置正确
outb(0x43, 0x36); // 通道0, lobyte/hibyte, 方波
uint16_t div = 1193182 / 100;
outb(0x40, div & 0xFF);
outb(0x40, (div >> 8) & 0xFF);错误 3:调度器在中断中死锁
症状
系统在调度时冻结。
原因
在调度过程中又收到了定时器中断,导致重入。
解决方案
调度器临界区必须关中断:
void schedule(void) {
__asm__ volatile("cli"); // 关中断
// ... 调度逻辑 ...
__asm__ volatile("sti"); // 开中断
}错误 4:ESP偏移量错误
症状
保存/恢复的ESP指向错误位置。
原因
switch.asm中process_t结构的esp字段偏移计算错误。
解决方案
使用offsetof确认:
// 在kernel.c中添加编译期检查
_Static_assert(offsetof(process_t, esp) == 40, "ESP offset mismatch!");错误 5:只有一个任务在运行
症状
创建了多个任务但只看到一个在运行。
原因
- 进程创建后没有加入就绪队列
- 就绪队列管理有bug(如tail指针未更新)
解决方案
// 创建后必须加入调度器
process_t *p = process_create("task", entry);
scheduler_add(p); // 别忘了这一步!调试技巧
在schedule()中添加打印:
screen_printf("[SCHED] %s -> %s\n", prev->name, next->name);