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

 

上一篇:CUDA略记


下一篇:高斯分布简述