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線程進行喚醒。

點擊(此處)摺疊或打開

  1. --------------linux/init/main.c---------------------

  2. static void do_pre_smp_initcalls(void)

  3. {

  4. extern int spawn_ksoftirqd(void);

  5. #ifdef CONFIG_SMP

  6. extern int migration_init(void);

  7. migration_init();

  8. #endif

  9. spawn_ksoftirqd();

  10. }



----------------linux/kernel/softirq.c----------------- /* 主cpu(即引導cpu)通過spawn_ksoftirqd()->cpu_callback()創建該cpu上的ksoftirqd 內核線程,並調用register_cpu_notifier() 將cpu_nfb註冊到cpu通知鏈) */

點擊(此處)摺疊或打開

  1. __init int spawn_ksoftirqd(void)

  2. {

  3. void *cpu =(void *)(long)smp_processor_id();

  4. cpu_callback(&cpu_nfb, CPU_UP_PREPARE, cpu);

  5. cpu_callback(&cpu_nfb, CPU_ONLINE, cpu);

  6. register_cpu_notifier(&cpu_nfb);

  7. return 0;

  8. }


----------------linux/kernel/softirq.c--------------------- //cpu_callback()建立了ksoftirqd內核線程,並把task_struct指針存於per_cpu變量per_cpu(ksoftirqd, hotcpu)中

點擊(此處)摺疊或打開

  1. static int __devinit cpu_callback(struct notifier_block *nfb,

  2.      unsigned long action,

  3.      void *hcpu)

  4. {

  5. int hotcpu =(unsigned long)hcpu;

  6. struct task_struct *p;

  7. switch (action){

  8. case CPU_UP_PREPARE:

  9.  BUG_ON(per_cpu(tasklet_vec, hotcpu).list);

  10.  BUG_ON(per_cpu(tasklet_hi_vec, hotcpu).list);

  11.  p = kthread_create(ksoftirqd, hcpu,"ksoftirqd/%d", hotcpu);

  12. if(IS_ERR(p)){

  13.   printk("ksoftirqd for %i failed\n", hotcpu);

  14.   return NOTIFY_BAD;

  15. }

  16.  kthread_bind(p, hotcpu);

  17.    per_cpu(ksoftirqd, hotcpu)= p;

  18.   break;

  19. case CPU_ONLINE:

  20.  wake_up_process(per_cpu(ksoftirqd, hotcpu));

  21.  break;

  22. #ifdef CONFIG_HOTPLUG_CPU

  23. case CPU_UP_CANCELED:

  24. /* Unbind so it can run. Fall thru.*/

  25.  kthread_bind(per_cpu(ksoftirqd, hotcpu), smp_processor_id());

  26. case CPU_DEAD:

  27.  p = per_cpu(ksoftirqd, hotcpu);

  28.  per_cpu(ksoftirqd, hotcpu)=NULL;

  29.  kthread_stop(p);

  30.  takeover_tasklets(hotcpu);

  31.  break;

  32. #endif /* CONFIG_HOTPLUG_CPU */

  33. }

  34. return NOTIFY_OK;

  35. }



2、從cpu的ksoftirqd線程的創建。從cpu調用start_kernel()->init()->smp_init()->cpu_up(),cpu_up()在各cpu上線前後分別調用notifier_call_chain()。


點擊(此處)摺疊或打開

  1. static void __init smp_init(void)

  2. {

  3. unsigned int i;

  4. /* FIXME: This should be done in userspace --RR */

  5. for_each_present_cpu(i){

  6. if(num_online_cpus()>= max_cpus)

  7.   break;

  8. if(!cpu_online(i))

  9.   cpu_up(i);

  10. }

  11. ……

  12. }

  13. int __devinit cpu_up(unsigned int cpu)

  14. {

  15. ……

  16. //上線前調用

  17. ret = notifier_call_chain(&cpu_chain, CPU_UP_PREPARE, hcpu);

  18. ……

  19. //等cpu上線:cpu_isset(cpu, cpu_online_map)

  20. ret = __cpu_up(cpu);

  21. ……

  22. /*Nowcall notifier in preparation.*/

  23. //上線後調用

  24. notifier_call_chain(&cpu_chain, CPU_ONLINE, hcpu);

  25. }


  26. //函數notifier_call_chain()以cpu標號爲參數運行cpu通知鏈上的各函數,其中包含上述spawn_ksoftirqd()中註冊的cpu_nfb。

  27. static struct notifier_block __devinitdata cpu_nfb ={

  28. .notifier_call = cpu_callback

  29. };


  30. //通知鏈元素cpu_nb上的函數cpu_callback即用來創建各非引導cpu上的ksoftirqd線程。

  31. int notifier_call_chain(struct notifier_block **n, unsigned long val, void *v)

  32. {

  33. int ret=NOTIFY_DONE;

  34. struct notifier_block *nb =*n;

  35. while(nb)

  36. {

  37.  ret=nb->notifier_call(nb,val,v);

  38. if(ret&NOTIFY_STOP_MASK)

  39. {

  40.   return ret;

  41. }

  42.  nb=nb->next;

  43. }

  44. return ret;

  45. }


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