Chinaunix首页 | 论坛 | 博客
  • 博客访问: 3170399
  • 博文数量: 685
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 5303
  • 用 户 组: 普通用户
  • 注册时间: 2014-04-19 14:17
个人简介

文章分类

全部博文(685)

文章存档

2015年(116)

2014年(569)

分类: LINUX

2015-02-05 17:26:36

原文地址:http://www.cnblogs.com/apprentice89/archive/2012/12/16/2820743.html

进程调度

 

clip_image001

三个组件:调度器、调度器类、上下文切换。

 

struct task_struct {

    ...

    int prio, static_prio, normal_prio;

    unsigned intrt_priority;

    struct list_head run_list;

    const struct sched_class *sched_class;

    struct sched_entity se//调度器不限于调度进程,可以处理更大的实体(组调度)。因此要求调度器不直接处理进程,而是处理se.

  

    unsigned intpolicy;

    cpumask_t cpus_allowed;  //sched_setaffinity

    unsigned inttime_slice;

    ...

}

 

 调度器类:

struct sched_class {

    conststruct sched_class *next;

    void (*enqueue_task) (struct rq *rq, struct task_struct *p, int wakeup);

    void (*dequeue_task) (struct rq *rq, struct task_struct *p, int sleep);

    void (*yield_task) (struct rq *rq);

    void (*check_preempt_curr) (struct rq *rq, struct task_struct *p);

    struct task_struct * (*pick_next_task) (struct rq *rq);

    void (*put_prev_task) (struct rq *rq, struct task_struct *p);

    void (*set_curr_task) (struct rq *rq);

   

//每次激活周期性调度器时,由周期性调度器调用task_tick

    void (*task_tick) (struct rq *rq, struct task_struct *p);

  

//fork产生新进程时,用task_new通知调度器

    void (*task_new) (struct rq *rq, struct task_struct *p);

};

 

 

 就绪队列:

struct rq {

    unsignedlongnr_running;

    #define CPU_LOAD_IDX_MAX 5

    unsignedlongcpu_load[CPU_LOAD_IDX_MAX];

  ...

    struct load_weight load;

    struct cfs_rq cfs;      //嵌入的队列,管理CFS

    struct rt_rq rt;    //嵌入的队列,管理实时调度

    struct task_struct *curr, *idle;

    u64 clock;

  ...

};

 

定义一个数组runqueues[],每个CPU都有一个struct rq.

 

static DEFINE_PER_CPU_SHARED_ALIGNED(struct rq, runqueues);

 

 

调度实体:

由于调度器可以操作比进程更一般的实体,因此需要一个适当的数据结构表示此类实体。

struct sched_entity {

    struct load_weight load;    // for load-balancing

 

    struct rb_node run_node;

    unsignedinton_rq;

    u64exec_start;

    u64sum_exec_runtime;

    u64vruntime;

    u64prev_sum_exec_runtime;

    ...

}

 

优先级:

clip_image003

 

负荷:

进程的优先级不仅由优先级指定,而且还要考虑保存在task_struct中的se.load的负荷权重。set_load_weight负责根据进程类型及其静态优先级计算负荷权重。

负荷权重

struct load_weight {

    unsignedlongweightinv_weight;

};

 

 

 

周期性调度器

按照一定频率自动调度(为省电可以关闭该调度器),在scheduler_tick中实现。

该函数调用委托到的具体底层调度器。

 

主调度器

内核要将CPU分给另一个进程、从系统调用返回时检查到TIF_NEED_RESCHED时,会调用schedule函数。

__sched前缀:用于标记可能调用schedule的函数(包括schedule函数自己),这些函数被放到sched.text代码段中,内核在显示栈转储时会忽略类似信息。

asmlinkage void __sched schedule(void){

  … 

prev->sched_class->put_prev_task(rq, prev); //通知调度器当前进程应被替换

next = pick_next_task(rq, prev); //调度器选择下一个应该被执行的进程

… 

rq->curr = next;

context_switch(rq, prev, next); //硬件级的进程切换

… 

}

 

 

上下文切换

static inline void context_switch(struct rq *rq, struct task_struct *prev, struct task_struct *next){

    …

    switch_mm(old_mm, mm, next);

    switch_to(prev, next, prev);

    barrier();

    finish_task_switch(this_rq(), prev);

}

 

 

switch_to之后的代码只有在当前进程再次被调度的时候,接着执行。



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