ICode9

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

migration/* kernel thread用途

2021-12-18 21:03:54  阅读:308  来源: 互联网

标签:kernel stopper thread work stop migration cpu


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

 

标签:kernel,stopper,thread,work,stop,migration,cpu
来源: https://www.cnblogs.com/aspirs/p/15705964.html

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

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

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

ICode9版权所有