Linux rest_init kernel_init与kthreadd启动
Linux rest_init kernel_init与kthreadd启动rest_init是start_kernel的最后一步,定义在init/main.c中。它在所有内核子系统初始化完成后被调用,负责创建两个最关键的内核线程——kernel_init(1号进程)和kthreadd(2号进程),然后将当前CPU控制权交给idle循环。函数实现如下:c// init/main.cstatic noinline void __init __noreturn rest_init(void){struct task_struct *tsk;int pid;// 第一步: 使用kernel_thread创建kernel_init(1号进程)// kernel_init负责启动用户空间的init程序pid kernel_thread(kernel_init, NULL,CLONE_FS | CLONE_FILES |CLONE_SIGHAND | CLONE_THREAD);rcu_assign_pointer(kernel_init_task,find_task_by_vpid(pid));// 第二步: 使用kernel_thread创建kthreadd(2号进程)// kthreadd是所有内核线程的父进程pid kernel_thread(kthreadd, NULL,CLONE_FS | CLONE_FILES |CLONE_SIGHAND);rcu_assign_pointer(kthreadd_task,find_task_by_vpid(pid));// 第三步: 将boot CPU的idle进程关联到current// 此时current即init_task// 通过PF_IDLE标志标识idle线程current-flags | PF_IDLE;// 第四步: 初始化pid_ns中的init进程组// 使kernel_init成为PID namespace的1号进程init_pid_ns.child_reaper current;// 第五步: 解锁所有在start_kernel期间被锁定的子系统// 允许kernel_init和kthreadd开始执行smp_mb();complete(kthreadd_done);complete(init_done);// 第六步: 进入idle循环// 至此,CPU0变为idle线程cpu_startup_entry(CPUHP_ONLINE);}kernel_init的执行路径决定了整个用户空间如何启动。它在得到调度后执行以下步骤:c// init/main.cstatic int __ref kernel_init(void *unused){int ret;// 等待kthreadd完全初始化wait_for_completion(kthreadd_done);// 初始化ramdisk/initramfs// 如果内核被编译为内嵌initramfs,在此展开if (ramdisk_execute_command) {ret run_init_process(ramdisk_execute_command);if (!ret)return 0;pr_err(Failed to execute %s\n,ramdisk_execute_command);}// 尝试依次执行多个可能的init程序路径// 按照优先级从高到低尝试if (execute_command) {// 如果cmdline指定了init,使用该路径ret run_init_process(execute_command);if (!ret)return 0;panic(Requested init %s failed (error %d).,execute_command, ret);}// 默认路径搜索顺序if (!try_to_run_init_process(/sbin/init) ||!try_to_run_init_process(/etc/init) ||!try_to_run_init_process(/bin/init) ||!try_to_run_init_process(/bin/sh))return 0;// 所有init路径都失败,内核panicpanic(No working init found. Try passing init option to kernel. See Linux Documentation/admin-guide/init.rst for guidance.);}// run_init_process是exec系统调用的封装static int __ref run_init_process(const char *init_filename){// 使用kernel_execve加载并执行init程序// argv和envp是标准的内核init参数char *argv[] { init_filename, NULL };char *envp[] { HOME/,TERMlinux,NULL };pr_info(Run %s as init process\n, init_filename);return kernel_execve(init_filename, argv, envp);}kthreadd是内核线程的守护进程,所有通过kthread_create创建的内核线程都是由kthreadd通过fork生成的:c// kernel/kthread.cint kthreadd(void *unused){struct task_struct *tsk;// 设置内存回收标志tsk current;tsk-flags | PF_NOFREEZE;// 通知kernel_init kthreadd已就绪complete(kthreadd_done);// 设置kthreadd的nice值,使其以较高优先级运行set_user_nice(tsk, -5);// 主循环: 处理kthread创建请求for (;;) {// 等待kthread_create_list上有新请求set_current_state(TASK_INTERRUPTIBLE);if (list_empty(kthread_create_list)) {// 没有待处理的创建请求,进入睡眠schedule();} else {// 有创建请求,退出等待状态__set_current_state(TASK_RUNNING);}// 处理所有待处理的kthread创建请求spin_lock(kthread_create_lock);while (!list_empty(kthread_create_list)) {struct kthread_create_info *create;// 从链表头部取出一个创建请求create list_entry(kthread_create_list.next,struct kthread_create_info, list);list_del_init(create-list);spin_unlock(kthread_create_lock);// 通过kernel_thread创建新的内核线程create_kthread(create);spin_lock(kthread_create_lock);}spin_unlock(kthread_create_lock);}return 0;}// 创建单个内核线程static void create_kthread(struct kthread_create_info *create){int pid;// 实际上通过kernel_thread调用kthread函数pid kernel_thread(kthread, create,CLONE_FS | CLONE_FILES |CLONE_SIGHAND | CLONE_VM);if (pid 0) {// 创建失败,通知等待者create-result ERR_PTR(pid);complete(create-done);}}// 每个内核线程的入口包装函数static int kthread(void *_create){struct kthread_create_info *create _create;int (*threadfn)(void *data);void *data;struct kthread_self *self;int ret;// 初始化kthread的自引用结构self kmalloc(sizeof(*self), GFP_KERNEL);self-threadfn threadfn;self-data data;// 通知kthreadd的调用者线程已创建完成create-result current;complete(create-done);// 执行实际的线程函数ret threadfn(data);// 线程退出do_exit(ret);}kernel_init和kthreadd创建并启动后,CPU0进入idle循环。其他CPU(AP)的热插拔初始化由smp_init在kernel_init中触发:c// init/main.cstatic int __ref kernel_init(void *unused){// 在启动1号进程之前,完成SMP初始化// 唤醒所有AP(应用处理器)smp_init();// 完成CPU热插拔状态机sched_init_smp();// 唤醒所有AP后,执行剩余初始化do_pre_smp_initcalls();// 执行所有level 0的initcalldo_basic_setup();// 最后,执行用户空间的init程序if (ramdisk_execute_command)run_init_process(ramdisk_execute_command);// ...}// smp_init唤醒AP核心void __init smp_init(void){unsigned int cpu;// 遍历所有可能的CPUfor_each_possible_cpu(cpu) {if (cpu smp_processor_id())continue;// 唤醒AP CPUif (!cpu_online(cpu)) {struct task_struct *idle;idle idle_thread_get(cpu);// 发送IPI唤醒APcpu_up(cpu);}}}rest_init完成后,整个Linux内核的初始化序列结束。系统状态如下:CPU0运行在idle线程中,1号进程kernel_init正在加载用户空间init程序,2号进程kthreadd等待创建内核线程的请求,其他CPU(如果有)也在各自的idle循环中等待调度。内核至此完成了从引导到完整操作系统的全部初始化过程。