本文共 3278 字,大约阅读时间需要 10 分钟。
linux内核中两大重要的线程,migration_thread负责cpu的负载均衡(将进程从本地队列移动到目标cpu的队列),kthreadd负责为kthread_create_list链表中的成员创建内核线程。
内核版本2.6.24中的引导部分,start_kernel()->rest_init():
点击(此处)折叠或打开
static void noinline __init_refok rest_init(void)
__releases(kernel_lock)
{
int pid;
kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND);
numa_default_policy();
pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES);
kthreadd_task = find_task_by_pid(pid);
……
}
以上依次创建了kernel_init线程和kthreadd线程,rest_init()是在禁用抢占(preempt_disable)的情况下运行,因此保证了kernel_init()运行时kthreadd_task
已经指向ktheadd线程。
kernel_init()
调用do_pre_smp_initcalls()->migration_init();创建了负责将进程在cpu间移动(cpu负载均衡)的内
核线程migration_thread(每个cpu一个),创建线程是通过将包含待运行函数及参数的kthread_create_info结构挂入
kthread_create_list链表,然后唤醒kthreadd_task(即ktheadd线程),而ktheadd线程负责为链表上的每个结
构创建相应的线程。
点击(此处)折叠或打开
void __init migration_init(void)
{
void *cpu = (void *)(long)smp_processor_id();
int err;
/* Start
one for the boot
CPU: */
err = migration_call(&migration_notifier, CPU_UP_PREPARE, cpu);
BUG_ON(err == NOTIFY_BAD);
migration_call(&migration_notifier, CPU_ONLINE, cpu);
register_cpu_notifier(&migration_notifier);
}
首 先直接调用migration_call两次创建了引导cpu的migration_thread线程并唤醒,然后调用
register_cpu_notifier()将migration_notifier挂入cpu_chain链表,在之后
kernel_init()->smp_init()中将依次对其余未上线的cpu调用cpu_up()->_cpu_up(),该函数分别
以参数CPU_UP_PREPARE和CPU_ONLINE调用两次__raw_notifier_call_chain(),实则是运行
cpu_chain链表上的函数,也包括了migration_call(),因此其余cpu的migration_thread也得以创建,最终是每个
cpu上都有一个migration_thread线程。
点击(此处)折叠或打开
static int __cpuinit
_cpu_up(unsigned int cpu, int tasks_frozen)
{
int ret, nr_calls = 0;
void *hcpu = (void *)(long)cpu;
unsigned
long mod = tasks_frozen ? CPU_TASKS_FROZEN : 0;
if (cpu_online(cpu) || !cpu_present(cpu))
return -EINVAL;
raw_notifier_call_chain(&cpu_chain, CPU_LOCK_ACQUIRE, hcpu);
ret = __raw_notifier_call_chain(&cpu_chain, CPU_UP_PREPARE | mod, hcpu,
-1, &nr_calls);
……
/* Now call notifier in preparation. */
raw_notifier_call_chain(&cpu_chain, CPU_ONLINE | mod, hcpu);
……
}
点击(此处)折叠或打开
static int __cpuinit
migration_call(struct
notifier_block *nfb, unsigned long
action, void *hcpu)
{
struct
task_struct *p;
int cpu = (long)hcpu;
unsigned
long flags;
struct
rq *rq;
switch (action) {
case CPU_LOCK_ACQUIRE:
mutex_lock(&sched_hotcpu_mutex);
break;
case CPU_UP_PREPARE:
case CPU_UP_PREPARE_FROZEN:
p = kthread_create(migration_thread, hcpu, "migration/%d", cpu);
if (IS_ERR(p))
return
NOTIFY_BAD;
kthread_bind(p, cpu);
/* Must
be high prio: stop_machine
expects to yield to it. */
rq = task_rq_lock(p, &flags);
__setscheduler(rq, p, SCHED_FIFO, MAX_RT_PRIO-1);
task_rq_unlock(rq, &flags);
cpu_rq(cpu)->migration_thread = p;
break;
case CPU_ONLINE:
case CPU_ONLINE_FROZEN:
/* Strictly
unnecessary, as first user
will wake it. */
wake_up_process(cpu_rq(cpu)->migration_thread);
break;
……
}
点击(此处)折叠或打开
struct task_struct *kthread_create(int (*threadfn)(void *data),
void *data,
const char
namefmt[],
...)
{
struct
kthread_create_info create;
create.threadfn = threadfn;
create.data = data;
init_completion(&create.started);
init_completion(&create.done);
spin_lock(&kthread_create_lock);
list_add_tail(&create.list, &kthread_create_list);
wake_up_process(kthreadd_task);
spin_unlock(&kthread_create_lock);
wait_for_completion(&create.done);
……
return
create.result;
}
转载地址:http://suhhp.baihongyu.com/