1. 程式人生 > >Linux idle程序建立過程(kernel 4.14)

Linux idle程序建立過程(kernel 4.14)

idle程序是核心建立的第一個程序,也常常被叫做swapper 程序:


asmlinkage __visible void __init start_kernel(void)
{
    char *command_line;
    char *after_dashes;

    set_task_stack_end_magic(&init_task);

idle程序也是唯一一個不是通過fork產生的程序,他是靜態定義的一個程序,init_task就是它的任務結構體。在start_kernel函式的最後:

asmlinkage __visible void __init start_kernel(void)
{
......

/* Do the rest non-__init'ed, we're now alive */
rest_init();

}

rest_init函式中會建立我們系統的第一個使用者空間程序,那就是大名鼎鼎的pid為1的init程序。init程序是所有使用者空間程序的祖先程序,而idle程序是所有程序的祖先程序。



static 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);


 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();
     ftrace_free_init_mem();
     free_initmem();
     mark_readonly();
     system_state = SYSTEM_RUNNING;
     numa_default_policy();
     rcu_end_inkernel_boot();

     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 (!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. "




在init程序建立完成後,該程序還會建立kthreadd程序,最後進入do_idle,也就是我們所說的idle程序所做的事情,讓cpu 進入idle狀態。

void cpu_startup_entry(enum cpuhp_state state)
{
    /*

     * This #ifdef needs to die, but it's too late in the cycle to

     * make this generic (arm and sh have never invoked the canary

     * init for the non boot cpus!). Will be fixed in 3.11

     */

#ifdef CONFIG_X86 

    /*

     * If we're the non-boot CPU, nothing set the stack canary up

     * for us. The boot CPU already has it initialized but no harm

     * in doing it again. This is a good place for updating it, as

     * we wont ever return from this function (so the invalid

     * canaries already on the stack wont ever trigger).

     */

    boot_init_stack_canary();
#endif
    arch_cpu_idle_prepare();
    cpuhp_online_idle(state);
    while (1)
        do_idle();
}