Chinaunix首页 | 论坛 | 博客
  • 博客访问: 20735
  • 博文数量: 3
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 10
  • 用 户 组: 普通用户
  • 注册时间: 2014-07-08 10:37
文章分类
文章存档

2015年(1)

2014年(2)

我的朋友

分类: LINUX

2015-05-07 13:36:00


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.  /* Now call notifier in preparation. */
  23.  //上线后调用
  24.  notifier_call_chain(&cpu_chain, CPU_ONLINE, hcpu);
  25. }
  26.  
  27. //函数notifier_call_chain()以cpu标号为参数运行cpu通知链上的各函数,其中包含上述spawn_ksoftirqd()中注册的cpu_nfb。
  28. static struct notifier_block __devinitdata cpu_nfb = {
  29.  .notifier_call = cpu_callback
  30. };

  31. //通知链元素cpu_nb上的函数cpu_callback即用来创建各非引导cpu上的ksoftirqd线程。
  32. int notifier_call_chain(struct notifier_block **n, unsigned long val, void *v)
  33. {
  34.  int ret=NOTIFY_DONE;
  35.  struct notifier_block *nb = *n;
  36.  while(nb)
  37.  {
  38.   ret=nb->notifier_call(nb,val,v);
  39.   if(ret&NOTIFY_STOP_MASK)
  40.   {
  41.    return ret;
  42.   }
  43.   nb=nb->next;
  44.  }
  45.  return ret;
  46. }


阅读(1559) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~