天天看点

linux内核schedule函数分析

asmlinkage void schedule(void)

{

 task_t *prev, *next;

 runqueue_t *rq;

 prio_array_t *array;

 struct list_head *queue;

 int idx;

 #判断是否调度发生在中断上下文,如果是就出错;在LINUX的中断中是不允许发生调度的

 if (unlikely(in_interrupt()))    

  BUG();

need_resched:

 preempt_disable();

 prev = current;

 rq = this_rq();

 release_kernel_lock(prev, smp_processor_id());

 prepare_arch_schedule(prev);

 prev->sleep_timestamp = jiffies;

 spin_lock_irq(&rq->lock);

 if (unlikely(preempt_get_count() & PREEMPT_ACTIVE))

  goto pick_next_task;

 switch (prev->state) {

 case TASK_INTERRUPTIBLE:

  if (unlikely(signal_pending(prev))) {

   prev->state = TASK_RUNNING;

   break;

  }

 default:

  deactivate_task(prev, rq);

 case TASK_RUNNING:

  ;

 }

pick_next_task:

 if (unlikely(!rq->nr_running)) {

#if CONFIG_SMP

  load_balance(rq, 1);

  if (rq->nr_running)

   goto pick_next_task;

#endif

  next = rq->idle;

  rq->expired_timestamp = 0;

  goto switch_tasks;

 }

 array = rq->active;

 if (unlikely(!array->nr_active)) {

  rq->active = rq->expired;

  rq->expired = array;

  array = rq->active;

  rq->expired_timestamp = 0;

 }

 idx = sched_find_first_bit(array->bitmap);

 queue = array->queue + idx;

 next = list_entry(queue->next, task_t, run_list);

switch_tasks:

 prefetch(next);

 clear_tsk_need_resched(prev);

 if (likely(prev != next)) {

  rq->nr_switches++;

  rq->curr = next;

  prepare_arch_switch(rq);

  TRACE_SCHEDCHANGE(prev, next);

  prev = context_switch(prev, next);

  barrier();

  rq = this_rq();

  finish_arch_switch(rq);

 } else

  spin_unlock_irq(&rq->lock);

 finish_arch_schedule(prev);

 reacquire_kernel_lock(current);

 preempt_enable_no_resched();

 if (need_resched())

  goto need_resched;

}

继续阅读