rest_init()
start_kernel() は最後に restinit() を実行してその生涯に幕を閉じる。
rest\init() では、init プロセスを起動するためのかーねるスレッドとカーネルスレッドデーモンを生成し、その後に CPU の休止とスケジューラ呼び出しを永久に繰り返すルーチンを呼び出す。
コードは init/main.c で定義されている。
static noinline void __init_refok rest_init(void)
{
...(中略)...
kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND);
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();
complete(&kthreadd_done);
/*
* The boot idle thread must execute schedule()
* at least once to get things moving:
*/
init_idle_bootup_task(current);
schedule_preempt_disabled();
/* Call into cpu_idle with preempt disabled */
cpu_startup_entry(CPUHP_ONLINE);
}
kernel_thread() はカーネルスレッドを生成するサブルーチン (do_fork() して第一引数の関数ポインタを実行する) であり、kernel_thread(kernel_init, NULL, CLONE_FS | CLONESIGHAND) では kernel\init() を実行するカーネルスレッドが生成される。
このスレッドは、カーネルに組み込まれているモジュールの初期化処理やルートファイルシステムのマウントを行い、最後に init プログラムを起動して、init プロセスに変化する。
pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES) では、kthreadd (カーネルスレッドデーモン) のスレッドが生成される。kthreadd はカーネルスレッドの生成処理を請け負うスレッドであり、init と kthreadd 以外のカーネルスレッドは全てこいつで生成される。
cpu_startup_entry()
rest_init() 内の cpu_startup_entry() で cpu_idle_loop() が non-preemption で呼ばれ、cpu_idle_loop() では以下のルーチンが永久に繰り返される。
- 実行可能状態のプロセスが現れるまで CPU を停止状態にする
- CPU の動作が再開されるとプロセス* スケジューラを呼び出して CPU を譲渡する
- その後実行可能なプロセスがなくなると cpu_idle_loop() に制御が戻るので、再び実行可能状態のプロセスが現れるまで CPU を停止状態にする
cpu_idle_loop() は kernel/cpu/idle.c で定義される。
static void cpu_idle_loop(void)
{
while (1) {
__current_set_polling();
tick_nohz_idle_enter();
while (!need_resched()) {
check_pgt_cache();
rmb();
if (cpu_is_offline(smp_processor_id()))
arch_cpu_idle_dead();
local_irq_disable();
arch_cpu_idle_enter();
if (cpu_idle_force_poll || tick_check_broadcast_expired()) {
cpu_idle_poll();
} else {
if (!current_clr_polling_and_test()) {
stop_critical_timings();
rcu_idle_enter();
arch_cpu_idle();
WARN_ON_ONCE(irqs_disabled());
rcu_idle_exit();
start_critical_timings();
} else {
local_irq_enable();
}
__current_set_polling();
}
arch_cpu_idle_exit();
}
tick_nohz_idle_exit();
__current_clr_polling();
smp_mb__after_atomic();
sched_ttwu_pending();
schedule_preempt_disabled();
}
}