Chinaunix首页 | 论坛 | 博客
  • 博客访问: 924059
  • 博文数量: 63
  • 博客积分: 568
  • 博客等级: 中士
  • 技术积分: 3435
  • 用 户 组: 普通用户
  • 注册时间: 2012-10-05 11:44
文章分类
文章存档

2016年(4)

2015年(6)

2014年(3)

2013年(27)

2012年(23)

分类: LINUX

2012-12-02 22:41:56

7. 调度

前面我们介绍了进程的创建,进程的唤醒,了解了linux进程管理的两个方面。这一节,我们看一下linux进程调度的处理过程。主要函数是scheduleschedule函数主要负责进程的调度,概要的说这个函数主要完成4个步骤。

1. 首先,取当前运行的进程,检查这个进程的状态还是不是RUNNING状态,如果不是了,说明当前进程被设置为休眠状态,这个时候再判断一下进程中是否pendingsignal,如果pendingsignal,将进程的状态设置运行状态。如果没有就调用deactivate_task函数,将进程从runqueue中取走。并设置p->se.on_rq = 0;

2. 然后,调用prev->sched_class->put_prev_task(rq, prev);这个函数实际调用了put_prev_task_fair,从函数的名称可以知道这个函数是对调度出去的进程进行相应的处理,这里分两种情况,一种情况就是这个进程实际上还处于RUNNIG状态,这时候需要把这个进程加入到runqueue中,如果进程已经进入休眠状态了,就不要再放入到runqueue中了。

3. 之后,调用pick_next_task,这个函数从名字上来看也能知道其作用,就是挑选下一个调度运行的函数。函数首先判断一下整个runqueue上进程的数目和cfs队列上的进程是不是相等。如果相等,说明其它调度队列上没有需要调度的进程,直接执行fair_sched_class.pick_next_task(rq),这个函数实际上就是pick_next_task_fair

 
/*
* Pick up the highest-prio task:
*/ 
static inline struct task_struct *
pick_next_task(struct rq *rq, struct task_struct *prev)
{
    const struct sched_class *class;
    struct task_struct *p;
 
    /*
     * Optimization: we know that if all tasks are in
     * the fair class we can call that function directly:
     */ 
    if (likely(rq->nr_running == rq->cfs.nr_running))
    {
        p = fair_sched_class.pick_next_task(rq);
        if (likely(p))
            return p;
    }
 
    class = sched_class_highest;
    for ( ; ; )
    {
        p = class->pick_next_task(rq);
        if (p)
            return p;
        /*
         * Will never be NULL as the idle class always
         * returns a non-NULL p:
         */ 
        class = class->next;
    }
}
 

pick_next_task_fair函数首先调用pick_next_entity,在pick_next_entity中首先从运行队列中(用红黑树管理)选出vruntime时间最小的那个task,然后再和cfs_rq->nextcfs_rq->last两个进程做比较。这里给予cfs_rq->next,和cfs_rq->last两个进程优先调度的机会,只要next或者last两个进程vruntime的时间没有比最小的vruntime大出调度的颗粒度时间,就会优先选择next或者last

__clear_buddies函数中会将cfs_rq->nextcfs_rq->last两个指针设置成为NULL

set_next_entity将选择的下一个运行的进程设置到curr指针。

 
static struct task_struct *pick_next_task_fair(struct rq *rq)
{
    struct task_struct *p;
    struct cfs_rq *cfs_rq = &rq->cfs;
    struct sched_entity *se;
 
    if (unlikely(!cfs_rq->nr_running))
        return NULL;
 
    do 
    {
        se = pick_next_entity(cfs_rq);
        /*
         * If se was a buddy, clear it so that it will have to earn
         * the favour again.
         */ 
        __clear_buddies(cfs_rq, se);
        set_next_entity(cfs_rq, se);
        cfs_rq = group_cfs_rq(se);
    }
    while (cfs_rq);
 
    p = task_of(se);
    hrtick_start_fair(rq, p);
 
    return p;
}
 

4. schedule函数的最后如果选择切换的进程和原来正在运行的进程不一样,就调用context_switch完成进程的切换。

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