linux kernel2.6中軟中斷運行線程ksoftirqd的創建

 1、軟中斷由內核線程ksoftirqd處理,下面說一下它的創建過程。
start_kernel()創建init線程,init()調用do_pre_smp_initcalls()->spawn_ksoftirqd(
),spawn_ksoftirqd()分兩次調用cpu_callback(),
分別使用參數CPU_UP_PREPARE和CPU_ONLINE。使用CPU_UP_PREPARE調用cpu_callback()
時,創建了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();
}
----------------linux/kernel/softirq.c-----------------
/*
主cpu(即引導cpu)通過spawn_ksoftirqd()->cpu_callback()創建該cpu上的ksoftirqd
內核線程,並調用register_cpu_notifier()
將cpu_nfb註冊到cpu通知鏈)
*/
__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);
 ……
 /* Now call 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;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章