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;
    }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM