Minix2组优先级调度实现遇异常:进程类型混乱及内核恐慌求助
问题排查与修复方案
核心问题分析
你遇到的子进程提前退出、进程类型识别混乱、内核恐慌等问题,根源集中在测试脚本逻辑缺陷和系统调用参数验证缺失两方面,具体如下:
1. 子进程提前退出的直接原因
测试脚本中,子进程被创建后没有持续运行的逻辑,会跟随父进程的循环执行完剩余迭代后直接return 0退出,自然无法进入调度循环。
2. 进程类型识别混乱与内核恐慌的根源
- 无PID合法性检查:系统调用直接使用
proc_addr(m_ptr->M2_l1)获取进程结构体,但未验证PID是否在合法范围(0~NR_PROCS-1),若PID无效(比如子进程未初始化完成、进程已退出),会指向内核中未初始化的空闲proc条目或系统task/serv的条目,导致内存访问混乱。 - 进程状态未校验:未检查目标进程是否处于活跃状态(
pr_state != PR_FREE),直接修改未初始化的proc字段,会让isuserp/istaskp等宏的判断结果随机(内存垃圾值刚好满足多个类型条件),甚至篡改系统核心进程的参数引发内核恐慌。 - 修改时机错误:父进程
fork后立刻调用系统修改子进程参数,此时子进程尚未完成MM进程的初始化流程,proc结构体字段未完全赋值,直接修改会破坏内核状态。
具体修复步骤
1. 修改测试脚本,让子进程持续运行
给子进程添加无限循环逻辑,避免提前退出:
#include <lib.h> #include <minix/callnr.h> #include <stdio.h> #include <signal.h> int main() { message m; int grp = 2; int add_prior = 2; time_t exec_time = 10; int counter = 1; pid_t main_pr = getpid(); printf("mainPID: %d\n", getpid()); for(counter; counter <= 30; counter++) { if(grp % 4 == 0) { grp++; } m.M1_i1 = (grp % 4); if(add_prior > 24) { add_prior = 2; } m.M1_i2 = (grp % 4) * 25 - add_prior; m.M1_i3 = exec_time; if(getpid() == main_pr) { m.M2_l1 = fork(); if(m.M2_l1 > 0) { // 等待子进程完成初始化 sleep(1); _syscall(MM, DO_SETPRI, &m); } else { // 子进程进入持续运行循环 while(1) { sleep(1); printf("Child PID %d is running\n", getpid()); } } } add_prior++; exec_time++; grp++; sleep(1); } return 0; }
2. 完善系统调用的参数验证与逻辑
给do_setprio添加严格的合法性检查,避免非法内存访问:
PRIVATE int do_setprio(m_ptr) register message *m_ptr; { struct proc *child_proc; pid_t target_pid = m_ptr->M2_l1; // 1. 检查PID是否在合法范围 if (target_pid < 0 || target_pid >= NR_PROCS) { return EINVAL; } child_proc = proc_addr(target_pid); // 2. 检查进程是否存在且为用户进程 if (child_proc->pr_state == PR_FREE || !isuserp(child_proc)) { return EINVAL; } // 此时进程类型只会是user,无需再判断task/serv printf("\n user process \n"); // 3. 修改进程调度参数 child_proc->pr_grp = m_ptr->M1_i1; child_proc->pr_priority = m_ptr->M1_i2; child_proc->pr_exec_time = m_ptr->M1_i3; printf("Data of process: PID:%d GRP:%d PRIOR:%d \n", target_pid, child_proc->pr_grp, child_proc->pr_priority); // 4. 修改优先级后触发重新调度 resched(); return 0; }
额外注意事项
- Minix的
proc结构体属于内核核心数据结构,直接修改需确保进程处于安全状态,避免在进程切换或内核操作过程中修改。 - 若需要更可靠的子进程初始化同步,可使用信号机制(比如子进程发送
SIGUSR1给父进程,父进程收到信号后再调用系统调用)。
内容的提问来源于stack exchange,提问作者Ivashchenko Matvii
相关产品推荐
相关产品推荐

