時,創建了ksoftirqd線程,並把task_struct指針存於per_cpu變量per_cpu(ksoftirqd,
hotcpu)中;使用CPU_ONLINE調用該函數對ksoftirqd線程進行喚醒。
點擊(此處)摺疊或打開
--------------linux/init/main.c---------------------
static void do_pre_smp_initcalls(void)
{
extern int spawn_ksoftirqd(void);
#ifdef CONFIG_SMP
extern int migration_init(void);
migration_init();
#endif
spawn_ksoftirqd();
}
點擊(此處)摺疊或打開
__init int spawn_ksoftirqd(void)
{
void *cpu =(void *)(long)smp_processor_id();
cpu_callback(&cpu_nfb, CPU_UP_PREPARE, cpu);
cpu_callback(&cpu_nfb, CPU_ONLINE, cpu);
register_cpu_notifier(&cpu_nfb);
return 0;
}
----------------linux/kernel/softirq.c--------------------- //cpu_callback()建立了ksoftirqd內核線程,並把task_struct指針存於per_cpu變量per_cpu(ksoftirqd, hotcpu)中
點擊(此處)摺疊或打開
static int __devinit cpu_callback(struct notifier_block *nfb,
unsigned long action,
void *hcpu)
{
int hotcpu =(unsigned long)hcpu;
struct task_struct *p;
switch (action){
case CPU_UP_PREPARE:
BUG_ON(per_cpu(tasklet_vec, hotcpu).list);
BUG_ON(per_cpu(tasklet_hi_vec, hotcpu).list);
p = kthread_create(ksoftirqd, hcpu,"ksoftirqd/%d", hotcpu);
if(IS_ERR(p)){
printk("ksoftirqd for %i failed\n", hotcpu);
return NOTIFY_BAD;
}
kthread_bind(p, hotcpu);
per_cpu(ksoftirqd, hotcpu)= p;
break;
case CPU_ONLINE:
wake_up_process(per_cpu(ksoftirqd, hotcpu));
break;
#ifdef CONFIG_HOTPLUG_CPU
case CPU_UP_CANCELED:
/* Unbind so it can run. Fall thru.*/
kthread_bind(per_cpu(ksoftirqd, hotcpu), smp_processor_id());
case CPU_DEAD:
p = per_cpu(ksoftirqd, hotcpu);
per_cpu(ksoftirqd, hotcpu)=NULL;
kthread_stop(p);
takeover_tasklets(hotcpu);
break;
#endif /* CONFIG_HOTPLUG_CPU */
}
return NOTIFY_OK;
}
2、從cpu的ksoftirqd線程的創建。從cpu調用start_kernel()->init()->smp_init()->cpu_up(),cpu_up()在各cpu上線前後分別調用notifier_call_chain()。
點擊(此處)摺疊或打開
static void __init smp_init(void)
{
unsigned int i;
/* FIXME: This should be done in userspace --RR */
for_each_present_cpu(i){
if(num_online_cpus()>= max_cpus)
break;
if(!cpu_online(i))
cpu_up(i);
}
……
}
int __devinit cpu_up(unsigned int cpu)
{
……
//上線前調用
ret = notifier_call_chain(&cpu_chain, CPU_UP_PREPARE, hcpu);
……
//等cpu上線:cpu_isset(cpu, cpu_online_map)
ret = __cpu_up(cpu);
……
/*Nowcall notifier in preparation.*/
//上線後調用
notifier_call_chain(&cpu_chain, CPU_ONLINE, hcpu);
}
//函數notifier_call_chain()以cpu標號爲參數運行cpu通知鏈上的各函數,其中包含上述spawn_ksoftirqd()中註冊的cpu_nfb。
static struct notifier_block __devinitdata cpu_nfb ={
.notifier_call = cpu_callback
};
//通知鏈元素cpu_nb上的函數cpu_callback即用來創建各非引導cpu上的ksoftirqd線程。
int notifier_call_chain(struct notifier_block **n, unsigned long val, void *v)
{
int ret=NOTIFY_DONE;
struct notifier_block *nb =*n;
while(nb)
{
ret=nb->notifier_call(nb,val,v);
if(ret&NOTIFY_STOP_MASK)
{
return ret;
}
nb=nb->next;
}
return ret;
}