smpboot_register_percpu_thread_cpumask的作用
2017-11-28 16:01
281 查看
int smpboot_register_percpu_thread_cpumask(struct smp_hotplug_thread *plug_thread, const struct cpumask *cpumask) 用于在cpumask表示的每个cpu上创建并运行一个thread 其用法如下: err = smpboot_register_percpu_thread_cpumask(&watchdog_threads, &watchdog_cpumask); 其中第一个参数watchdog_threads的定于如下: static struct smp_hotplug_thread watchdog_threads = { .store = &softlockup_watchdog, .thread_should_run = watchdog_should_run, .thread_fn = watchdog, .thread_comm = "watchdog/%u", .setup = watchdog_enable, .cleanup = watchdog_cleanup, .park = watchdog_disable, .unpark = watchdog_enable, }; 下来我们看看smpboot_register_percpu_thread_cpumask 执行的过程 int smpboot_register_percpu_thread_cpumask(struct smp_hotplug_thread *plug_thread, const struct cpumask *cpumask) { unsigned int cpu; int ret = 0; #申请一个plug_thread->cpumask 后,通过cpumask_copy将cpumask 里面的值赋值给plug_thread->cpumask if (!alloc_cpumask_var(&plug_thread->cpumask, GFP_KERNEL)) return -ENOMEM; cpumask_copy(plug_thread->cpumask, cpumask); get_online_cpus(); mutex_lock(&smpboot_threads_lock); #遍历所有online,为每个online的cpu建立一个thread for_each_online_cpu(cpu) { ret = __smpboot_create_thread(plug_thread, cpu); if (ret) { smpboot_destroy_threads(plug_thread); free_cpumask_var(plug_thread->cpumask); goto out; #如果online cpu不再cpumask中的话,则unpark 这个thread if (cpumask_test_cpu(cpu, cpumask)) smpboot_unpark_thread(plug_thread, cpu); } #将所有通过smpboot_register_percpu_thread_cpumask 创建的thread都添加到hotplug_threads 中 list_add(&plug_thread->list, &hotplug_threads); out: mutex_unlock(&smpboot_threads_lock); put_online_cpus(); return ret; } 下来继续看看__smpboot_create_thread static int __smpboot_create_thread(struct smp_hotplug_thread *ht, unsigned int cpu) { struct task_struct *tsk = *per_cpu_ptr(ht->store, cpu); struct smpboot_thread_data *td; if (tsk) return 0; #申请一个smpboot_thread_data *td ,作为thread的参数 td = kzalloc_node(sizeof(*td), GFP_KERNEL, cpu_to_node(cpu)); if (!td) return -ENOMEM; td->cpu = cpu; td->ht = ht; #在特定的cpu上创建thread,注意这个thread的回调函数是smpboot_thread_fn tsk = kthread_create_on_cpu(smpboot_thread_fn, td, cpu, ht->thread_comm); if (IS_ERR(tsk)) { kfree(td); return PTR_ERR(tsk); } /* * Park the thread so that it could start right on the CPU * when it is available. */ kthread_park(tsk); get_task_struct(tsk); *per_cpu_ptr(ht->store, cpu) = tsk; //如果ht->create 不为null的话,调用ht->create,本例子中ht->create为null,具体可以参看watchdog_threads 并没有实现create函数 if (ht->create) { /* * Make sure that the task has actually scheduled out * into park position, before calling the create * callback. At least the migration thread callback * requires that the task is off the runqueue. */ if (!wait_task_inactive(tsk, TASK_PARKED)) WARN_ON(1); else ht->create(cpu); } return 0; } 继续看看回调函数smpboot_thread_fn,这个回调函数是一个死循环 static int smpboot_thread_fn(void *data) { struct smpboot_thread_data *td = data; struct smp_hotplug_thread *ht = td->ht; while (1) { set_current_state(TASK_INTERRUPTIBLE); preempt_disable(); if (kthread_should_stop()) { __set_current_state(TASK_RUNNING); preempt_enable(); /* cleanup must mirror setup */ if (ht->cleanup && td->status != HP_THREAD_NONE) ht->cleanup(td->cpu, cpu_online(td->cpu)); kfree(td); return 0; } if (kthread_should_park()) { __set_current_state(TASK_RUNNING); preempt_enable(); if (ht->park && td->status == HP_THREAD_ACTIVE) { BUG_ON(td->cpu != smp_processor_id()); ht->park(td->cpu); td->status = HP_THREAD_PARKED; } kthread_parkme(); /* We might have been woken for stop */ continue; } BUG_ON(td->cpu != smp_processor_id()); #根据td->status判断是否要运行客户定义的函数,这里就是watchdog_threads的.thread_fn = watchdog, /* Check for state change setup */ switch (td->status) { case HP_THREAD_NONE: __set_current_state(TASK_RUNNING); preempt_enable(); if (ht->setup) ht->setup(td->cpu); td->status = HP_THREAD_ACTIVE; continue; case HP_THREAD_PARKED: __set_current_state(TASK_RUNNING); preempt_enable(); if (ht->unpark) ht->unpark(td->cpu); td->status = HP_THREAD_ACTIVE; continue; } if (!ht->thread_should_run(td->cpu)) { preempt_enable_no_resched(); schedule(); } else { __set_current_state(TASK_RUNNING); preempt_enable(); #这里是核心调用watchdog_threads的.thread_fn = watchdog, ht->thread_fn(td->cpu); } } } 到这里应该明白smpboot_register_percpu_thread_cpumask的作用了,这个函数可以简化用户在每个cpu上创建thread的工作量.
相关文章推荐
- SetThreadAffinityMask设置使用多核CPU的哪个核心
- SetThreadAffinityMask设置使用多核CPU的哪个核心
- SetThreadAffinityMask设置使用多核CPU的哪个核心
- start_kernel——boot_cpu_init及PER_CPU
- smp_prepare_boot_cpu
- start_kernel——boot_cpu_init及PER_CPU
- 多cpu下SetThreadAffinityMask运用框架
- SetThreadAffinityMask 把线程限定在CPU上运行
- 48.VC(custom)-SetThreadAffinityMask 把线程限定在CPU上运行
- [原创]如何解决LodRunner中报错关于Error -10489 : Exception was raised when calling per-thread-terminate function
- kernel中的per_cpu变量
- 内核源码--------mm_init_cpumask(&init_mm);
- SMP系统linux下的进程绑定指定cpu
- uboot启动流程详解(4)-cpu_init_crit
- C语言中关键字auto、static、register、const、volatile、extern的作用
- Spring Boot中的initializers的作用分析
- cocos2dx- call to OpenGL ES API with no current context(logged once per thread)
- Unable to boot : please use a kernel appropriate for your cpu
- Linux per_cpu机制的详解
- 为什么per_cpu_ptr写那么变态on UP