• migration/* kernel thread用途


    migration/* kernel thread用途

    console:/proc/13 # ps -Af |grep migration
    root            13     2 0 02:29:43 ?     00:00:00 [migration/0]
    root            16     2 0 02:29:43 ?     00:00:00 [migration/1]
    root            21     2 0 02:29:43 ?     00:00:00 [migration/2]
    root            26     2 0 02:29:43 ?     00:00:00 [migration/3]

    内核线程migration/*是一个工作线程,可以将工作发给它让它执行,将工作发给它有两种API,如下,这个两个API的差异是一个会等这个work function调用完成,它有一个完成量(completion),可以理解为同步方式;而另外一个是不等它完成,queue到migration/*线程的work queue并wake它就会返回,可以理解为异步方式。这两个API会根据其cpu参数找到这个cpu的per cpu变量struct cpu_stopper,然后将此work加到此cpu_stopper变量的works链表上

    这两个API参数含义:

    cpu: 表示这个work你要给与这个cpu绑定的migration thread去处理

    fn: work function,work所做的事情;

    arg:传给fn的参数,即fn(arg):

    int stop_one_cpu(unsigned int cpu, cpu_stop_fn_t fn, void *arg);
    bool stop_one_cpu_nowait(unsigned int cpu, cpu_stop_fn_t fn, void *arg,
                struct cpu_stop_work *work_buf);

    至于migration/*线程是怎么创建的以及有什么特性描述如下:

    它是和cpu core绑定的,每个cpu core都会有这样一个线程,另外这些kernel thread sched class是stop_sched_class,sched policy是SCHED_FIFO(RT),priority是99,是RT priority里最低的优先级。在cpu_stop_threads.cpu_stop_create函数里设置此thread的sched class、policy、priority:

    kernel/sched/core.c

    void sched_set_stop_task(int cpu, struct task_struct *stop)
    {
        struct sched_param param = { .sched_priority = MAX_RT_PRIO - 1 };
        struct task_struct *old_stop = cpu_rq(cpu)->stop;
    
        if (stop) {
            /*
             * Make it appear like a SCHED_FIFO task, its something
             * userspace knows about and won't get confused about.
             *
             * Also, it will make PI more or less work without too
             * much confusion -- but then, stop work should not
             * rely on PI working anyway.
             */
            sched_setscheduler_nocheck(stop, SCHED_FIFO, &param);
    
            stop->sched_class = &stop_sched_class;
        }
    
        cpu_rq(cpu)->stop = stop;
    
        if (old_stop) {
            /*
             * Reset it back to a normal scheduling class so that
             * it can die in pieces.
             */
            old_stop->sched_class = &rt_sched_class;
        }
    }

    4.19/kernel/stop_machine.c

    static void cpu_stop_create(unsigned int cpu)
    {
        sched_set_stop_task(cpu, per_cpu(cpu_stopper.thread, cpu));
    }
    static struct smp_hotplug_thread cpu_stop_threads = {
        .store            = &cpu_stopper.thread,
        .thread_should_run    = cpu_stop_should_run,
        .thread_fn        = cpu_stopper_thread,
        .thread_comm        = "migration/%u",
        .create            = cpu_stop_create,
        .park            = cpu_stop_park,
        .selfparking        = true,
    };
    static int __init cpu_stop_init(void)
    {
        unsigned int cpu;
    
        for_each_possible_cpu(cpu) {
            struct cpu_stopper *stopper = &per_cpu(cpu_stopper, cpu);
    
            raw_spin_lock_init(&stopper->lock);
            INIT_LIST_HEAD(&stopper->works);
        }
    
        BUG_ON(smpboot_register_percpu_thread(&cpu_stop_threads));
        stop_machine_unpark(raw_smp_processor_id());
        stop_machine_initialized = true;
        return 0;
    }
    early_initcall(cpu_stop_init);

    使用stop_one_cpu()或者stop_one_cpu_nowait()将work发给目标migration线程并wake它后,migration线程将会wakeup执行cpu_stopper_thread(),从works链表中取出work,并执行其work function:

    static void cpu_stopper_thread(unsigned int cpu)
    {
        struct cpu_stopper *stopper = &per_cpu(cpu_stopper, cpu);
        struct cpu_stop_work *work;
    
    repeat:
        work = NULL;
        raw_spin_lock_irq(&stopper->lock);
        if (!list_empty(&stopper->works)) {
            work = list_first_entry(&stopper->works,
                        struct cpu_stop_work, list);
            list_del_init(&work->list);
        }
        raw_spin_unlock_irq(&stopper->lock);
    
        if (work) {
            cpu_stop_fn_t fn = work->fn;
            void *arg = work->arg;
            struct cpu_stop_done *done = work->done;
            int ret;
    
            /* cpu stop callbacks must not sleep, make in_atomic() == T */
            preempt_count_inc();
            ret = fn(arg);
            if (done) {
                if (ret)
                    done->ret = ret;
                cpu_stop_signal_done(done);
            }
            preempt_count_dec();
            WARN_ONCE(preempt_count(),
                  "cpu_stop: %pf(%p) leaked preempt count\n", fn, arg);
            goto repeat;
        }
    }
  • 相关阅读:
    CF869E The Untended Antiquity 解题报告
    Walk 解题报告
    CF911F Tree Destruction 解题报告
    P4397 [JLOI2014]聪明的燕姿
    洛谷 P2329 [SCOI2005]栅栏 解题报告
    洛谷 P3747 [六省联考2017]相逢是问候 解题报告
    set-erase
    set-empty
    set-empty
    set-end
  • 原文地址:https://www.cnblogs.com/aspirs/p/15705964.html
Copyright © 2020-2023  润新知