smp启动-smp_init-idle_threads_init-cpuhp_threads_init
作者:互联网
上一篇:smp_init 的整体流程
https://www.cnblogs.com/zhangzhiwei122/p/16093602.html
本文: smp_init 中的 idle thread init 每个cpu的idle_threads
cpuhp_threads_init 每个cpu的 cpuhp task
smp_init
805 idle_threads_init 为每个非boot cpu都各fork一个idle task,将获得的task_struct记录到per_cpu变量idle_threads中
806 cpuhp_threads_init 为每个core都创建一个"cpuhp/%u"内核线程,结果记录在per_cpu变量cpuhp_state.thread中,然后启动当前cpu的"cpuhp/%u"线程:"cpuhp/0"
810 bringup_noboot_cpus(setup_max_cpus) - 函数实现在 kernel/cpu.c ,
对每个 present cpu ,检查是否已经 cpu_online 了,如果没有,就调用cpu_up(cpu, CPUHP_ONLINE)
/kernel/smp.c
800/* Called by boot processor to activate the rest. */ 801void __init smp_init(void) 802{ 803 int num_nodes, num_cpus; 804 805 idle_threads_init(); 806 cpuhp_threads_init(); 807 808 pr_info("Bringing up secondary CPUs ...\n"); 809 810 bringup_nonboot_cpus(setup_max_cpus); 811
kernel/cpu.c
1335void bringup_nonboot_cpus(unsigned int setup_max_cpus) 1336{ 1337 unsigned int cpu; 1338 1339 for_each_present_cpu(cpu) { 1340 if (num_online_cpus() >= setup_max_cpus) 1341 break; 1342 if (!cpu_online(cpu)) 1343 cpu_up(cpu, CPUHP_ONLINE); 1344 } 1345}
idle_threads_init
kernel/smpboot.c
28static DEFINE_PER_CPU(struct task_struct *, idle_threads); 45/** 46 * idle_init - Initialize the idle thread for a cpu 47 * @cpu: The cpu for which the idle thread should be initialized 48 * 49 * Creates the thread if it does not exist. 50 */ 51static inline void idle_init(unsigned int cpu) 52{ 53 struct task_struct *tsk = per_cpu(idle_threads, cpu); 54 55 if (!tsk) { 56 tsk = fork_idle(cpu); 57 if (IS_ERR(tsk)) 58 pr_err("SMP: fork_idle() failed for CPU %u\n", cpu); 59 else 60 per_cpu(idle_threads, cpu) = tsk; 61 } 62} 63 64/** 65 * idle_threads_init - Initialize idle threads for all cpus 66 */ 67void __init idle_threads_init(void) 68{ 69 unsigned int cpu, boot_cpu; 70 71 boot_cpu = smp_processor_id(); 72 73 for_each_possible_cpu(cpu) { 74 if (cpu != boot_cpu) 75 idle_init(cpu); 76 } 77}
28 - 定义 per cpu变量 task_struct 指针,idle_threads
67 - idle_threads_init 实现。代码比较简单,可以理解。
60 - fork_idle 成功后,将tsk 指针放到 cpu对应的 idle_threads 里面。
cpuhp_threads_init
/kernel/cpu.c
802static struct smp_hotplug_thread cpuhp_threads = { 803 .store = &cpuhp_state.thread, 804 .create = &cpuhp_create, 805 .thread_should_run = cpuhp_should_run, 806 .thread_fn = cpuhp_thread_fun, 807 .thread_comm = "cpuhp/%u", 808 .selfparking = true, 809}; 811void __init cpuhp_threads_init(void) 812{ 813 BUG_ON(smpboot_register_percpu_thread(&cpuhp_threads)); 814 kthread_unpark(this_cpu_read(cpuhp_state.thread)); 815}
802 行定义了对象struct smp_hotplug_thread cpuhp_threads 并对其进行了初始化
813 行,将 802 行对象的指针,丢给 smpboot_register_percpu_thread 函数。里面会将 cpuhp_threads 加入到链表 hotplug_threads 里面,供后面使用。
对已经online 的cpu 【即boot cpu】 创建 task ,将task 指针 放到 cpuhp_state.thread 里面。unpark 这个 task
(备注:803 行,store 里面存放的是 task_struct 指针的地址。 per cpu 变量是一个 task 指针。这个指针的 地址 即是它的 offset,
所以store 里面存放的是原始变量的offset 。
per_cpu_ptr(offset , cpu ) 取得 指定cpu 的副本的 task 指针的 地址。
* per_cpu_ptr(offset , cpu ) ,指定cpu 副本的 task 指针的 值。)
814 kthread_unpark 让 this_cpu 的 cpuhp_state.thread 指示的 task 运行起来。
smpboot_register_percpu_thread
kernel/smpboot.c
289int smpboot_register_percpu_thread(struct smp_hotplug_thread *plug_thread) 290{ 291 unsigned int cpu; 292 int ret = 0; 293 294 get_online_cpus(); 295 mutex_lock(&smpboot_threads_lock); 296 for_each_online_cpu(cpu) { 297 ret = __smpboot_create_thread(plug_thread, cpu); 298 if (ret) { 299 smpboot_destroy_threads(plug_thread); 300 goto out; 301 } 302 smpboot_unpark_thread(plug_thread, cpu); 303 } 304 list_add(&plug_thread->list, &hotplug_threads); 305out: 306 mutex_unlock(&smpboot_threads_lock); 307 put_online_cpus(); 308 return ret; 309}
304 - 将 传入的 plug_thread 加入到 hotplug_threads 链表里面。后面
cpu_up //kernel/cpu.c
-> _cpu_up //kernel/cpu.c
-> cpuhp_up_callbacks
-> cpuhp_invoke_callback
->struct cpuhp_step cpuhp_hp_states [CPUHP_CREATE_THREADS] {.startup.single = smpboot_create_threads,}
-> int smpboot_create_threads(unsigned int cpu) // kernel/smpboot.c 中会使用到 hotplug_threads 链表
296 ~ 302 对于 online 的cpu, 直接 __smpboot_create_thread(plug_thread, cpu) 给 cpu 创建 task ,成功后,
使用 smpboot_unpark_thread(plug_thread, cpu) 让指定的cpu 执行 task .
在这个阶段,只有 0 号cpu, 即 boot cpu 处在 online 阶段,只对 boot cpu 进行 plug_thread 的创建。
对于现在还没有 online 的cpu, 则需要指向 cpu_up 操作,也就是 smp 启动 过程
__smpboot_create_thread 过程大致
173 行 - hotplug_thread 的store 里面存放的是 一个指针, cpuhp_state.thread
per_cpu_ptr 又 取得指针的地址,
前面 * 号,又取出 指针值放到 tsk 。
176 ~ 177 检查,如果非空,表示已经创建了 task_struct 对象,直接返回 。
185 - 到这儿,说明 cpuhp_state.thread 的值为 0, 使用 kthread_create_on_cpu 创建 task,返回指针赋值给 tsk
197 - 将 185 得到的 task_struct 指针,赋值给 cpuhp_state.thread 这个per cpu 变量
170static int 171__smpboot_create_thread(struct smp_hotplug_thread *ht, unsigned int cpu) 172{ 173 struct task_struct *tsk = *per_cpu_ptr(ht->store, cpu); 176 if (tsk) 177 return 0; 185 tsk = kthread_create_on_cpu(smpboot_thread_fn, td, cpu, 186 ht->thread_comm); 195 kthread_park(tsk); 196 get_task_struct(tsk); 197 *per_cpu_ptr(ht->store, cpu) = tsk; 198 if (ht->create) { 208 ht->create(cpu); 209 } 210 return 0; 211}
1335void bringup_nonboot_cpus(unsigned int setup_max_cpus) 1336{ 1337 unsigned int cpu; 1338 1339 for_each_present_cpu(cpu) { 1340 if (num_online_cpus() >= setup_max_cpus) 1341 break; 1342 if (!cpu_online(cpu)) 1343 cpu_up(cpu, CPUHP_ONLINE); 1344 } 1345}
标签:cpuhp,thread,idle,smp,init,threads,cpu 来源: https://www.cnblogs.com/zhangzhiwei122/p/16095130.html