ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

smp启动-smp_init-idle_threads_init-cpuhp_threads_init

2022-04-03 09:35:40  阅读:255  来源: 互联网

标签:cpuhp thread idle smp init threads cpu


 

上一篇: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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有