Chinaunix首页 | 论坛 | 博客
  • 博客访问: 326423
  • 博文数量: 135
  • 博客积分: 867
  • 博客等级: 准尉
  • 技术积分: 865
  • 用 户 组: 普通用户
  • 注册时间: 2012-03-15 14:50
文章分类

全部博文(135)

文章存档

2012年(135)

分类: LINUX

2012-07-23 17:06:32

一个时钟中断产生时,会对被中断的进程进行时间片计算,如果时间片用完,那就应该引起进程切换,就是你这里提到的“rescheduling activity”

具体代码路径如下:
  1. timer_interrupt() ---> do_timer_interrupt()  --->do_timer_interrupt_hook() ---> update_process_times() ---> scheduler_tick()

  2. void scheduler_tick(void)
  3. {
  4.         int cpu = smp_processor_id();
  5.         runqueue_t *rq = this_rq();
  6.         task_t *p = current;
  7.         unsigned long long now = sched_clock();

  8.         update_cpu_clock(p, rq, now);

  9.         rq->timestamp_last_tick = now;

  10.         if (p == rq->idle) {
  11.                 if (wake_priority_sleeper(rq))
  12.                         goto out;
  13.                 rebalance_tick(cpu, rq, SCHED_IDLE);
  14.                 return;
  15.         }

  16.         /* Task might have expired already, but not scheduled off yet */
  17.         if (p->array != rq->active) {
  18.                 set_tsk_need_resched(p);
  19.                 goto out;
  20.         }
  21.         spin_lock(&rq->lock);
  22.         /*
  23.          * The task was running during this tick - update the
  24.          * time slice counter. Note: we do not update a thread's
  25.          * priority until it either goes to sleep or uses up its
  26.          * timeslice. This makes it possible for interactive tasks
  27.          * to use up their timeslices at their highest priority levels.
  28.          */
  29.         if (rt_task(p)) {
  30.                 /*
  31.                  * RR tasks need a special form of timeslice management.
  32.                  * FIFO tasks have no timeslices.
  33.                  */
  34.                 if ((p->policy == SCHED_RR) && !--p->time_slice) {
  35.                         p->time_slice = task_timeslice(p);
  36.                         p->first_time_slice = 0;
  37.                         set_tsk_need_resched(p);

  38.                         /* put it at the end of the queue: */
  39.                         requeue_task(p, rq->active);
  40.                 }
  41.                 goto out_unlock;
  42.         }
  43.         if (!--p->time_slice) {
  44.                 dequeue_task(p, rq->active);
  45.                 set_tsk_need_resched(p);
  46.                 p->prio = effective_prio(p);
  47.                 p->time_slice = task_timeslice(p);
  48.                 p->first_time_slice = 0;

  49.                 if (!rq->expired_timestamp)
  50.                         rq->expired_timestamp = jiffies;
  51.                 if (!TASK_INTERACTIVE(p) || EXPIRED_STARVING(rq)) {
  52.                         enqueue_task(p, rq->expired);
  53.                         if (p->static_prio < rq->best_expired_prio)
  54.                                 rq->best_expired_prio = p->static_prio;
  55.                 } else
  56.                         enqueue_task(p, rq->active);
  57.         } else {
  58.                 /*
  59.                  * Prevent a too long timeslice allowing a task to monopolize
  60.                  * the CPU. We do this by splitting up the timeslice into
  61.                  * smaller pieces.
  62.                  *
  63.                  * Note: this does not mean the task's timeslices expire or
  64.                  * get lost in any way, they just might be preempted by
  65.                  * another task of equal priority. (one with higher
  66.                  * priority would have preempted this task already.) We
  67.                  * requeue this task to the end of the list on this priority
  68.                  * level, which is in essence a round-robin of tasks with
  69.                  * equal priority.
  70.                  *
  71.                  * This only applies to tasks in the interactive
  72.                  * delta range with at least TIMESLICE_GRANULARITY to requeue.
  73.                  */
  74.                 if (TASK_INTERACTIVE(p) && !((task_timeslice(p) -
  75.                         p->time_slice) % TIMESLICE_GRANULARITY(p)) &&
  76.                         (p->time_slice >= TIMESLICE_GRANULARITY(p)) &&
  77.                         (p->array == rq->active)) {

  78.                         requeue_task(p, rq->active);
  79.                         set_tsk_need_resched(p);
  80.                 }
  81.         }
  82. out_unlock:
  83.         spin_unlock(&rq->lock);
  84. out:
  85.         rebalance_tick(cpu, rq, NOT_IDLE);
  86. }


  87. 这里面有几个地方都调用了set_tsk_need_resched(p)

  88. static inline void set_tsk_need_resched(struct task_struct *tsk)
  89. {
  90.         set_tsk_thread_flag(tsk,TIF_NEED_RESCHED);
  91. }


  92. static inline void set_tsk_thread_flag(struct task_struct *tsk, int flag)
  93. {
  94.         set_ti_thread_flag(task_thread_info(tsk), flag);
  95. }

  96. static inline void set_ti_thread_flag(struct thread_info *ti, int flag)
  97. {
  98.         set_bit(flag,&ti->flags);
  99. }
复制代码
最后,在中断处理结束的点上,调用了ret_from_intr(在entry.S中)
  1. ret_from_intr:
  2.         GET_THREAD_INFO(%ebp)
  3.         movl EFLAGS(%esp), %eax                # mix EFLAGS and CS
  4.         movb CS(%esp), %al
  5.         testl $(VM_MASK | 3), %eax
  6.         jz resume_kernel
  7. ENTRY(resume_userspace)
  8.         cli                                # make sure we don't miss an interrupt
  9.                                         # setting need_resched or sigpending
  10.                                         # between sampling and the iret
  11.         movl TI_flags(%ebp), %ecx
  12.         andl $_TIF_WORK_MASK, %ecx        # is there any work to be done on
  13.                                         # int/exception return?
  14.         jne work_pending
  15.         jmp restore_all

  16. #ifdef CONFIG_PREEMPT
  17. ENTRY(resume_kernel)
  18.         cli
  19.         cmpl $0,TI_preempt_count(%ebp)        # non-zero preempt_count ?
  20.         jnz restore_nocheck
  21. need_resched:
  22.         movl TI_flags(%ebp), %ecx        # need_resched set ?
  23.         testb $_TIF_NEED_RESCHED, %cl
  24.         jz restore_all
  25.         testl $IF_MASK,EFLAGS(%esp)     # interrupts off (exception path) ?
  26.         jz restore_all
  27.         call preempt_schedule_irq
  28.         jmp need_resched
  29. #endif
复制代码
可以看到,最后是通过call preempt_schedule_irq进行进程切换的
  1. asmlinkage void __sched preempt_schedule_irq(void)
  2. {
  3.         struct thread_info *ti = current_thread_info();
  4. #ifdef CONFIG_PREEMPT_BKL
  5.         struct task_struct *task = current;
  6.         int saved_lock_depth;
  7. #endif
  8.         /* Catch callers which need to be fixed*/
  9.         BUG_ON(ti->preempt_count || !irqs_disabled());

  10. need_resched:
  11.         add_preempt_count(PREEMPT_ACTIVE);
  12.         /*
  13.          * We keep the big kernel semaphore locked, but we
  14.          * clear ->lock_depth so that schedule() doesnt
  15.          * auto-release the semaphore:
  16.          */
  17. #ifdef CONFIG_PREEMPT_BKL
  18.         saved_lock_depth = task->lock_depth;
  19.         task->lock_depth = -1;
  20. #endif
  21.         local_irq_enable();
  22.         [b]schedule();[/b]        local_irq_disable();
  23. #ifdef CONFIG_PREEMPT_BKL
  24.         task->lock_depth = saved_lock_depth;
  25. #endif
  26.         sub_preempt_count(PREEMPT_ACTIVE);

  27.         /* we could miss a preemption opportunity between schedule and now */
  28.         barrier();
  29.         if (unlikely(test_thread_flag(TIF_NEED_RESCHED)))
  30.                 goto need_resched;
  31. }
复制代码
Hi, Linux!
阅读(1424) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~