Linux中的三个特殊进程:
idle进程:
该进程是Linux中的第一个进程(线程),PID为0;
idle进程是init进程和kthreadd进程(内核线程)的父进程;
init进程:
init进程是Linux中第一个用户空间的进程,PID为1;
init进程是其他用户空间进程的直接或间接父进程;
kthreadd(内核线程):
kthreadd线程是内核空间其他内核线程的直接或间接父进程,PID为2;
kthreadd线程负责内核线程的创建工作;
idle进程、init进程、kthreadd进程的创建
ARM架构中idle进程的创建
https://elixir.bootlin.com/linux/latest/source/arch/arm64/kernel/head.S#L472
在start_kernel函数中调用了rest_init函数,在rest_init函数中创建了kernel_init、kthreadd内核线程
https://elixir.bootlin.com/linux/latest/source/init/main.c#L674
noinline void __ref rest_init(void) { struct task_struct *tsk; int pid; rcu_scheduler_starting(); /* * We need to spawn init first so that it obtains pid 1, however * the init task will end up wanting to create kthreads, which, if * we schedule it before we create kthreadd, will OOPS. */ pid = kernel_thread(kernel_init, NULL, CLONE_FS); /* * Pin init on the boot CPU. Task migration is not properly working * until sched_init_smp() has been run. It will set the allowed * CPUs for init to the non isolated CPUs. */ rcu_read_lock(); tsk = find_task_by_pid_ns(pid, &init_pid_ns); set_cpus_allowed_ptr(tsk, cpumask_of(smp_processor_id())); rcu_read_unlock(); numa_default_policy(); pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES); rcu_read_lock(); kthreadd_task = find_task_by_pid_ns(pid, &init_pid_ns); rcu_read_unlock(); /* * Enable might_sleep() and smp_processor_id() checks. * They cannot be enabled earlier because with CONFIG_PREEMPTION=y * kernel_thread() would trigger might_sleep() splats. With * CONFIG_PREEMPT_VOLUNTARY=y the init task might have scheduled * already, but it's stuck on the kthreadd_done completion. */ system_state = SYSTEM_SCHEDULING; complete(&kthreadd_done); /* * The boot idle thread must execute schedule() * at least once to get things moving: */ schedule_preempt_disabled(); /* Call into cpu_idle with preempt disabled */ cpu_startup_entry(CPUHP_ONLINE); }
1号内核线程是如何成为用户空间的init进程的?
init进程在kernel_init函数中启动
https://elixir.bootlin.com/linux/latest/source/init/main.c#L1409
static int __ref kernel_init(void *unused) { int ret; kernel_init_freeable(); /* need to finish all async __init code before freeing the memory */ async_synchronize_full(); kprobe_free_init_mem(); ftrace_free_init_mem(); free_initmem(); mark_readonly(); /* * Kernel mappings are now finalized - update the userspace page-table * to finalize PTI. */ pti_finalize(); system_state = SYSTEM_RUNNING; numa_default_policy(); rcu_end_inkernel_boot(); do_sysctl_args(); if (ramdisk_execute_command) { ret = run_init_process(ramdisk_execute_command); if (!ret) return 0; pr_err("Failed to execute %s (error %d)\n", ramdisk_execute_command, ret); } /* * We try each of these until one succeeds. * * The Bourne shell can be used instead of init if we are * trying to recover a really broken machine. */ if (execute_command) { ret = run_init_process(execute_command); if (!ret) return 0; panic("Requested init %s failed (error %d).", execute_command, ret); } if (CONFIG_DEFAULT_INIT[0] != '\0') { ret = run_init_process(CONFIG_DEFAULT_INIT); if (ret) pr_err("Default init %s failed (error %d)\n", CONFIG_DEFAULT_INIT, ret); else return 0; } /* 调用系统根目录下的init文件,会在以下几个路径中加载init进程 */ /* 在Android源码中,init进程源码的位置为:https://www.androidos.net.cn/android/10.0.0_r6/xref/system/core/init/init.cpp */ 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; panic("No working init found. Try passing init= option to kernel. " "See Linux Documentation/admin-guide/init.rst for guidance."); }
kthreadd内核线程的启动
https://elixir.bootlin.com/linux/latest/source/kernel/kthread.c#L605
int kthreadd(void *unused) { struct task_struct *tsk = current; /* Setup a clean context for our children to inherit. */ set_task_comm(tsk, "kthreadd"); ignore_signals(tsk); set_cpus_allowed_ptr(tsk, housekeeping_cpumask(HK_FLAG_KTHREAD)); set_mems_allowed(node_states[N_MEMORY]); current->flags |= PF_NOFREEZE; cgroup_init_kthreadd(); for (;;) { set_current_state(TASK_INTERRUPTIBLE); if (list_empty(&kthread_create_list)) /* 判断内核线程链表是否为空 */ schedule(); /* 若没有需要创建的内核线程,进行一次调度,让出cpu */ __set_current_state(TASK_RUNNING); 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); /* 只要kthread_create_list不为空,就根据表中元素创建内核线程 */ create_kthread(create); spin_lock(&kthread_create_lock); } spin_unlock(&kthread_create_lock); } return 0; }
本文介绍了Linux操作系统中的三个关键进程:idle进程,作为所有进程的起点,PID为0;init进程,作为用户空间的第一个进程,PID为1,并作为其他用户进程的父进程;以及kthreadd内核线程,PID为2,负责创建其他内核线程。在ARM架构中,idle进程的创建始于start_kernel函数调用rest_init,而init进程则在kernel_init函数中启动,kthreadd线程的创建则在kernel/kthread.c中进行。

5549

被折叠的 条评论
为什么被折叠?



