linux IDLE 0号进程分析

linux操作系统中第一个进程是0号进程是为道,其主要任务是不断进行进程调度。

第一个cpu上的IDLE进程

内核在启动过程中第一个cpu进入start_kernel逻辑,这个逻辑是内核初始化入口。

内核初始化的过程逻辑比较复杂,......略。

在执行该内核初始化逻辑前,0号进程已经绑定到当前的cpu上了。

// init/main.c
// 在第一个cpu上执行 该进程是0号进程
void start_kernel(void) {
   ...
// 初始化操作
   ...
   arch_call_rest_init();
}

0号进程的调度逻辑:

// init/main.c
void arch_call_rest_init(void) {
 rest_init();
}

// init/main.c
void rest_init(void) {
 int pid;
//    ...

//  0号进程创建1号进程init
    pid = kernel_thread(kernel_init,...);

//    ...

//  0号进程创建2号进程kthreadd
    pid = kernel_thread(kthreadd,...);
    ...
//  调度逻辑
    cpu_startup_entry(CPUHP_ONLINE);
}

1号和2号进程

PPID是指父进程的ID,通过执行ps -ef可以发现,用户态进程的祖先都是1号init进程。

僵尸/孤儿进程最后都会被init进程清理和托管。

    僵尸进程管理

    父子进程两者运行是相互独立的,父进程不清楚子进程什么时候结束。

    子进程退出后,父进程会使用wait或waitpid进行回收子进程资源,获得子进程终止状态。

    子进程先于父进程退出,父进没有使用使用wait或waitpid回收子进程资源,子进程会残留资源        存放于内核中,变成僵尸进程。

    子进程调用exit结束时,内核释放了该进程所有资源,包括打开的文件、占用的内存等。

    子进程信有些息直到父进程通过 wait()/waitpid()才会被释放,进程号、退出状态、运行时间。

    孤儿进程管理

    父进程退出,它的子进程还在运行变成孤儿进程。

    内核会把孤儿进程的父进程设置为init,完成状态收集工作。

init进程还给其它cpu创建IDLE进程。

IDLE进程while循环尝试进程调度,保证cpu一直有机器指令在执行。

道生一二0号进程创建了1号和2号进程,然后调用cpu_startup_entry:

// kernel/sched/idle.c
void cpu_startup_entry(...) {
    // 0号是优先级最低的进程 当没有进程被调度时 就选择0号进程
    // 0号进程while循环 不断地执行调度操作
    // 由此0号进程被叫做IDLE进程
    while (1)
        do_idle();
}
// kernel/sched/idle.c
static void do_idle(void) {
    ...
    schedule_idle();
    ...
}

// kernel/sched/core.c
void schedule_idle(void) {
    ...
    __schedule(false);
    ...
}

其它cpu上的IDLE进程

上述可知第一个cpu有个IDLE进程不断的执行while循环。

其它cpu也有IDLE进程不断的执行,道生万物这些IDLE进程都是第一个cpu的IDLE进程创建出来的。

在rest_init方法中第一个cpu的IDLE进程调用kernel_thread创建了1号进程。

入口函数为kernel_init()也叫INIT进程:

// init/main.c
static int kernel_init(void *unused) {
    ...
    kernel_init_freeable();
    ...
}

// init/main.c
static void kernel_init_freeable(void) {
    ...
    smp_init();
    ...
}

// kernel/smp.c
void smp_init(void) {
//    ...
//  创建其他IDLE进程 
    idle_threads_init(); 
    pr_info("Bringing up secondary CPUs ...\n");

//    ...
//  启动其他cpu
    for_each_present_cpu(cpu) {
    ...
        cpu_up(cpu);
    }
}

在smp_inits中通过idle_threads_init过方法复制出IDLE进程们。

如操作系统有8个cpu,除第一个cpu当前进程外,要复制出7个IDLE进程。

如某cpu没有绑定IDLE进程,则调用fork_idle创建调用per_cpu绑定。

// kernel/smpboot.c
void idle_threads_init(void) {
    unsigned int cpu, boot_cpu;

    boot_cpu = smp_processor_id();

    for_each_possible_cpu(cpu) {
       if (cpu != boot_cpu)
           idle_init(cpu);
     }
}

// kernel/smpboot.c
static void idle_init(unsigned int cpu) {
    struct task_struct *tsk = per_cpu(idle_threads, cpu);

    if (!tsk) {
        // 复制进程 
        tsk = fork_idle(cpu);
        per_cpu(idle_threads, cpu) = tsk;
    }
}

IDLE进程们初始化完成后加载其余cpu。

入口函数是secondary_start_kernel:

// arch/arm64/kernel/smp.c
void secondary_start_kernel(void) {
    ...
    cpu_startup_entry(CPUHP_AP_ONLINE_IDLE);
}

// kernel/sched/idle.c
void cpu_startup_entry(...) {
    while (1)
        do_idle();
}

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值