You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 07:17:04