代码改变世界

Kernel rest_init相关

2016-09-29 15:38  cascle  阅读(705)  评论(0编辑  收藏  举报

Linux系统里,有些进程只有kernel部分的代码,即由一个kernel函数进入,在sched的时候,将其与用户进程同等对待。

PID为0的叫swapper或sched进程,对应函数为rest_init

init进程PID为1,

kthreadd进程PID为2,

0号进程,即rest_init主体如下

 1 static noinline void __init_refok rest_init(void)
 2 {
 3     int pid;
 4 
 5     rcu_scheduler_starting();
 6     smpboot_thread_init();
 7     /*
 8      * We need to spawn init first so that it obtains pid 1, however
 9      * the init task will end up wanting to create kthreads, which, if
10      * we schedule it before we create kthreadd, will OOPS.
11      */
12     kernel_thread(kernel_init, NULL, CLONE_FS);
13     numa_default_policy();
14     pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES);
15     rcu_read_lock();
16     kthreadd_task = find_task_by_pid_ns(pid, &init_pid_ns);
17     rcu_read_unlock();
18     complete(&kthreadd_done);
19 
20     /*
21      * The boot idle thread must execute schedule()
22      * at least once to get things moving:
23      */
24     init_idle_bootup_task(current);
25     schedule_preempt_disabled();
26     /* Call into cpu_idle with preempt disabled */
27     cpu_startup_entry(CPUHP_ONLINE);

先是rcu_scheduler_starting函数,这个函数的作用是

再是smpboot_thread_init函数,这个函数注册smpboot时候的notifier,响应CPU动作

1 static struct notifier_block smpboot_thread_notifier = {
2     .notifier_call = smpboot_thread_call,
3     .priority = CPU_PRI_SMPBOOT,
4 };
5 
6 void __cpuinit smpboot_thread_init(void)
7 {
8     register_cpu_notifier(&smpboot_thread_notifier);
9 }

 然后调用kernel_thread函数fork init进程

1 /*
2  * Create a kernel thread.
3  */
4 pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
5 {
6     return do_fork(flags|CLONE_VM|CLONE_UNTRACED, (unsigned long)fn,
7         (unsigned long)arg, NULL, NULL);
8 }


do_fork函数被调用

 

这里有一点要注意,init进程执行的时候要等kerneladd进程执行后才被complete(&kthreadd_done)唤醒,然后真正执行,不然直接调度到init的话会OOPs

numa_default_policy被调用设置内存numa默认策略

然后调用kernel_thread函数fork kthreadd进程

然后用find_task_by_pid_ns(pid, &init_pid_ns)获取kthreadd的task_struct

最后唤醒complete(&kthreadd_done)进程

最后,0号进程,即空闲进程,要让一切跑起来,调用一次schedule