Chinaunix首页 | 论坛 | 博客
  • 博客访问: 39231
  • 博文数量: 5
  • 博客积分: 70
  • 博客等级: 民兵
  • 技术积分: 106
  • 用 户 组: 普通用户
  • 注册时间: 2012-11-01 11:42
文章分类
文章存档

2017年(2)

2013年(2)

2012年(1)

我的朋友

分类: LINUX

2012-12-26 15:15:42

linux内核中两大重要的线程,migration_thread负责cpu的负载均衡(将进程从本地队列移动到目标cpu的队列),kthreadd负责为kthread_create_list链表中的成员创建内核线程。

内核版本2.6.24中的引导部分,start_kernel()->rest_init():

点击(此处)折叠或打开

  1. static void noinline __init_refok rest_init(void)
  2.         __releases(kernel_lock)
  3. {
  4.         int pid;

  5.         kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND);
  6.         numa_default_policy();
  7.         pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES);
  8.         kthreadd_task = find_task_by_pid(pid);
  9. ……
  10. }

以上依次创建了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线程负责为链表上的每个结构创建相应的线程。

点击(此处)折叠或打开

  1. void __init migration_init(void)
  2. {
  3.         void *cpu = (void *)(long)smp_processor_id();
  4.         int err;

  5.         /* Start one for the boot CPU: */
  6.         err = migration_call(&migration_notifier, CPU_UP_PREPARE, cpu);
  7.         BUG_ON(err == NOTIFY_BAD);
  8.     migration_call(&migration_notifier, CPU_ONLINE, cpu);
  9.     register_cpu_notifier(&migration_notifier);
  10. }

首先直接调用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线程。

点击(此处)折叠或打开

  1. static int __cpuinit _cpu_up(unsigned int cpu, int tasks_frozen)
  2. {
  3.     int ret, nr_calls = 0;
  4.     void *hcpu = (void *)(long)cpu;
  5.     unsigned long mod = tasks_frozen ? CPU_TASKS_FROZEN : 0;

  6.     if (cpu_online(cpu) || !cpu_present(cpu))
  7.         return -EINVAL;

  8.     raw_notifier_call_chain(&cpu_chain, CPU_LOCK_ACQUIRE, hcpu);
  9.     ret = __raw_notifier_call_chain(&cpu_chain, CPU_UP_PREPARE | mod, hcpu,
  10.                             -1, &nr_calls);
  11. ……
  12. /* Now call notifier in preparation. */
  13.     raw_notifier_call_chain(&cpu_chain, CPU_ONLINE | mod, hcpu);
  14. ……
  15. }


/*
1、以CPU_UP_PREPARE为参数调用时,创建migration_thread线程,并绑定到cpu,设置调用策略为实时进程SCHED_FIFO,
优先级99,cpu运行队列的migration_thread指向该内核线程,此时线程是不可中断睡眠状态。
2、以CPU_ONLINE为参数调用时,唤醒cpu_rq(cpu)->migration_thread指向的migration_thread线程。
*/

点击(此处)折叠或打开

  1. static int __cpuinit
  2. migration_call(struct notifier_block *nfb, unsigned long action, void *hcpu)
  3. {
  4.         struct task_struct *p;
  5.         int cpu = (long)hcpu;
  6.         unsigned long flags;
  7.         struct rq *rq;

  8.         switch (action) {
  9.         case CPU_LOCK_ACQUIRE:
  10.                 mutex_lock(&sched_hotcpu_mutex);
  11.                 break;

  12.         case CPU_UP_PREPARE:
  13.             case CPU_UP_PREPARE_FROZEN:
  14.         p = kthread_create(migration_thread, hcpu, "migration/%d", cpu);
  15.         if (IS_ERR(p))
  16.             return NOTIFY_BAD;
  17.         kthread_bind(p, cpu);
  18.         /* Must be high prio: stop_machine expects to yield to it. */
  19.         rq = task_rq_lock(p, &flags);
  20.         __setscheduler(rq, p, SCHED_FIFO, MAX_RT_PRIO-1);
  21.         task_rq_unlock(rq, &flags);
  22.         cpu_rq(cpu)->migration_thread = p;
  23.         break;

  24.     case CPU_ONLINE:
  25.     case CPU_ONLINE_FROZEN:
  26.         /* Strictly unnecessary, as first user will wake it. */
  27.         wake_up_process(cpu_rq(cpu)->migration_thread);
  28.         break;
  29. ……
  30. }


/*创建线程是通过将包含线程运行函数和参数的kthread_create_info结构挂入kthread_create_list链表,
并唤醒内核线程kthreadd_task对链表上的各个线程创建需求进行处理来实现的,当创建成功后返回进程指针,
这是通过wait_for_completion(&create.done)进行同步的。此内核线程创建函数不负责将线程绑定到cpu,绑定工作
须由调用函数负责。
*/

点击(此处)折叠或打开

  1. struct task_struct *kthread_create(int (*threadfn)(void *data),
  2.                                    void *data,
  3.                                    const char namefmt[],
  4.                                    ...)
  5. {
  6.         struct kthread_create_info create;

  7.         create.threadfn = threadfn;
  8.         create.data = data;
  9.         init_completion(&create.started);
  10.         init_completion(&create.done);

  11.         spin_lock(&kthread_create_lock);
  12.         list_add_tail(&create.list, &kthread_create_list);
  13.         wake_up_process(kthreadd_task);
  14.         spin_unlock(&kthread_create_lock);

  15.     wait_for_completion(&create.done);
  16. ……
  17.         return create.result;
  18. }

阅读(6017) | 评论(0) | 转发(1) |
0

上一篇:没有了

下一篇:linux kernel2.6中软中断运行线程ksoftirqd的创建

给主人留下些什么吧!~~