smpboot_register_percpu_thread_cpumask的作用

来源:互联网 发布:js隐藏显示tr 编辑:程序博客网 时间:2024/05/17 06:00
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->cpumaskif (!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建立一个threadfor_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 这个threadif (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_threadstatic 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_fntsk = 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);elseht->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的工作量.

原创粉丝点击