- 论坛徽章:
- 0
|
最近学习linux内核源代码,发现对kernel_init()里的wait_for_completion(&kthreadd_done)不是很理解,请大侠给解释一下。
先说说我的疑惑:
在start_kernel()函数里先调用preempt_disable()禁止内核抢占,并在start_kernel的最后调用了rest_init();
与rest_init函数相关的代码如下:
static __initdata DECLARE_COMPLETION(kthreadd_done);
static noinline void __init_refok rest_init(void)
{
int pid;
rcu_scheduler_starting();
/*
* We need to spawn init first so that it obtains pid 1, however
* the init task will end up wanting to create kthreads, which, if
* we schedule it before we create kthreadd, will OOPS.
*/
1: kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND);
numa_default_policy();
2: pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES);
rcu_read_lock();
kthreadd_task = find_task_by_pid_ns(pid, &init_pid_ns);
rcu_read_unlock();
3: complete(&kthreadd_done);
/*
* The boot idle thread must execute schedule()
* at least once to get things moving:
*/
init_idle_bootup_task(current);
4: schedule_preempt_disabled();
/* Call into cpu_idle with preempt disabled */
cpu_idle();
}
rest_init里利用kernel_thread创建了kernel_init和kthreadd两个线程。从rest_init里的注释可看到kernel_init线程不能在kthreadd线程创建完成前被调度,否则会产生oops.(注:标号1/2/3/4是我加上去的,方便后文描述)
与kernel_init函数相关的内容:
static int __init kernel_init(void * unused)
{
/*
* Wait until kthreadd is all set-up.
*/
wait_for_completion(&kthreadd_done);
.
.
.
}
在kernel_init函数的入口处就开始等待kthreadd_done完成量,也就是说如果kernel_init先于标号3前被调度的话,必须等kthreadd_done完成后才能继续往下走。可问题来了,start_kernel里是先关抢占后才调用rest_init函数创建kernel_init线程的,也就是说在标号4处重新开抢占前,kernel_init线程不可能先于idle线程运行,即kernel_init线程肯定是在kthreadd线程创建完成后才被调度执行,如果是这样的话,此处的完成量就没有起到作用。那为什么还在kernel_init的入口处弄这么一完成量呢?
也许是我的理解有误,请大侠们给排一下疑。
|
|