Fork me on GitHub

迁移线程migration

每个处理器有一个迁移线程,线程名称是“migration/<cpu_id>”,属于停机调度类,可以抢占所有其他进程,其他进程不可以抢占它。迁移线程有两个作用。

(1)调度器发出迁移请求,迁移线程处理迁移请求,把进程迁移到目标处理器。

(2)执行主动负载均衡。

如图所示,每个处理器有一个停机工作管理器,成员thread指向迁移线程的进程描述符,成员works是停机工作队列的头节点,每个节点是一个停机工作,数据类型是结构体

cpu_stop_work。内核提供了两个添加停机工作的函数。

stop_one_cpu
--cpu_stop_queue_work
---__cpu_stop_queue_work
----list_add_tail and wake_up_process

在stop_one_cpu中,迁移作业将打包为工作,并调用cpu_stop_queue_work以获取CPU的停止线程。 然后,调用__cpu_stop_queue_work将此工作放入此CPU上的停止线程的工作队列中。 最后,唤醒停止线程进行迁移。 停止器线程在Linux内核中称为迁移线程(请参阅以下源代码)。

504 static struct smp_hotplug_thread cpu_stop_threads = {
505         .store                  = &amp;cpu_stopper.thread,
506         .thread_should_run      = cpu_stop_should_run,
507         .thread_fn              = cpu_stopper_thread,
508         .thread_comm            = "migration/%u",
509         .create                 = cpu_stop_create,
510         .park                   = cpu_stop_park,
511         .selfparking            = true,
512 };
513 
514 static int __init cpu_stop_init(void)
515 {
516         unsigned int cpu;
517 
518         for_each_possible_cpu(cpu) {
519                 struct cpu_stopper *stopper = &amp;per_cpu(cpu_stopper, cpu);
520 
521                 spin_lock_init(&amp;stopper-&gt;lock);
522                 INIT_LIST_HEAD(&amp;stopper-&gt;works);
523         }
524 
525         BUG_ON(smpboot_register_percpu_thread(&amp;cpu_stop_threads));
526         stop_machine_unpark(raw_smp_processor_id());
527         stop_machine_initialized = true;
528         return 0;
529 }
530 early_initcall(cpu_stop_init);

我们发现每个CPU上的Linux Kernel迁移线程都是通过early_initcall初始化的,这是在启动内核时完成的,如下所示。

start_kernel
--rest_init
---kernel_init
----kernel_init_freeable
-----do_pre_smp_initcalls
------do_one_initcall

Linux Kernel迁移线程守护程序是要初始化的early_initcall之一。 Linux内核有许多初始化调用,如下所示。

814 static char *initcall_level_names[] __initdata = {
815         "early",
816         "core",
817         "postcore",
818         "arch",
819         "subsys",
820         "fs",
821         "device",
822         "late",
823 };

到目前为止,我认为一切都已经清楚了,启动内核后,Linux内核中的迁移守护进程线程将被初始化。 一旦完成迁移工作,它就会被唤醒以进行迁移工作(注意:在这里,我只考虑sched_setaffinity的情况,也许Linux内核中还有其他方法可以唤醒迁移线程守护程序)。 此外,对于其他内核线程守护程序(例如softirqd,kworker等),它们具有由Linux Kernel创建的类似方式(例如迁移线程守护程序)。

结论在Linux内核中,每个CPU都有一个迁移线程守护程序来执行资源平衡作业。 如果我们调用sched_setaffinity系统调用将一个线程从源CPU迁移到目标CPU,并且该线程正在运行或处于TASK_WAKING状态,则迁移作业将打包到源CPU的迁移线程的工作队列中,然后,迁移线程将被唤醒以完成迁移工作。

posted @ 2024-10-23 10:43  yooooooo  阅读(7)  评论(0编辑  收藏  举报