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}

 bringup_noboot_cpus -> cpu_up

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}

 

 

下一篇:smp启动-secondary cpu 启动流程和boot cpu的交互点

https://www.cnblogs.com/zhangzhiwei122/p/16095273.html

 

posted @ 2022-04-03 09:05  张志伟122  阅读(375)  评论(0编辑  收藏  举报