linux 内核的入口函数是每个体系结构自己定义的,假设当前架构的内核入口函数是:kernel_entry(),则下面梳理了从核的初始化过程(内核版本:4.19):
kernel_entry()
|_ start_kernel()
|_ rest_init()
|_ kernel_init() // 新线程
| |_ smp_init()
| |_ cpuhp_threads_init()
| | |_ smpboot_register_percpu_thread()
| | |_ kthread_create_on_cpu()
| | |_ kthread_create_on_node()
| | |_ __kthread_create_on_node()
| | |_ 将 create 信息放在 kthread_create_list 链表上
| |_ cpu_up()
| |_ do_cpu_up()
| |_ _cpu_up()
| |_ cpuhp_set_state()
| |_ 将从核的 target (在 cpuhp_cpu_state 结构体中) 设置为 CPUHP_ONLINE(最大值)
|_ kthreadd() // 新线程
|_ 遍历 kthread_create_list 链表,依次取下每个 create 信息
|_ create_thread()
|_ kthread() // 新线程
|_ 执行 create 信息中的 threadfn 函数指针
|_ smpboot_thread_fn()
|_ cpuhp_thread_fun()
|_ cpuhp_invoke_callback()
|_ pv_cpu_online()
在从核线程中:
smpboot_thread_fn() 会循环(while(1))调用 cpuhp_thread_fun(),后者在每次被调用时都会更新当前 cpu 的 state (在 cpuhp_cpu_state 结构体中),当 state 大于 target 后,结束循环。其中 target 的值由主核设置为:CPUHP_ONLINE。
在主核线程中:
调用 _cpu_up() 时也做了从核的部分初始化工作,代码如下所示:
static int _cpu_up(unsigned int cpu, int tasks_frozen, enum cpuhp_state target)
{
...
// 设置从核的 target
cpuhp_set_state(st, target);
/*
* Try to reach the target state. We max out on the BP at
* CPUHP_BRINGUP_CPU. After that the AP hotplug thread is
* responsible for bringing it up to the target state.
*/
target = min((int)target, CPUHP_BRINGUP_CPU);
ret = cpuhp_up_callbacks(cpu, st, target);
...
}
从上面的注释可以看到,主核将从核的状态初始化到了 CPUHP_BRINGUP_CPU,而 CPUHP_BRINGUP_CPU+1 到 CPUHP_ONLINE 之间的状态由从核自己初始化。