Chinaunix首页 | 论坛 | 博客
  • 博客访问: 291150
  • 博文数量: 49
  • 博客积分: 3083
  • 博客等级: 中校
  • 技术积分: 710
  • 用 户 组: 普通用户
  • 注册时间: 2007-07-27 08:22
文章分类

全部博文(49)

文章存档

2009年(8)

2008年(41)

分类: LINUX

2008-12-24 11:05:05

 

Linux进程调度在编译时可以有多种选择,可以有实时调度模块(Real-Time Scheduling Class,见sched_rt.c),空闲任务调度(idle-task scheduling class,sched_idletask.c),以及在这里要分析的完全公平调度(Completely Fair Scheduling,sched_fair.c)

 

进程调度的主函数为schedule()位于sched.c中。Schedule()通过sched_init()对不同sched_class的选择来对进程进行调度的。当然,首先得通过#ifdef来对当前编译所制定的进程调度方式进行选择

 

#ifdef CONFIG_FAIR_GROUP_SCHED

static void init_tg_cfs_entry(struct task_group *tg, struct cfs_rq *cfs_rq,

                                     struct sched_entity *se, int cpu, int add,

                                     struct sched_entity *parent)

{……}

#endif

 

#ifdef CONFIG_RT_GROUP_SCHED

static void init_tg_rt_entry(struct task_group *tg, struct rt_rq *rt_rq,

                   struct sched_rt_entity *rt_se, int cpu, int add,

                   struct sched_rt_entity *parent)

{……}

#endif

 

sched_init()中,则针对不同的CONFIG参数,对调度方式进行初始化。在设置完不同CONFIG参数的功能后,则用include"sched_stats.h""sched_idletask.c" "sched_fair.c""sched_rt.c”文件包含进sched.c。,并对一些需要用到的函数进行定义,同时对SMP中的CPU选定,任务的迁移,等待没有激活的进程等函数进行定义。

 

         整个的sched.c函数,实现进程的唤醒try_to_wake_up(),执行有关调度设置一个新分叉的进程页p,不将其插入运行时队列。wake_up_new_task()则是唤醒一个新创建进程第一次运行。finish_task_switch()完成进程的切换。context_switch()上下文的选择。接着则是对在SMP中的任务的平衡、迁移、寻找最繁忙的组等,应该说在sched.c中对smp的具体实现费了很大的功夫,不过作为进程的调度,也是应当多考虑到多处理器间负载的平衡,否则多处理器的性能将会大打折扣,无法发挥其应用的性能。针对SMP来说调度程序不仅仅是在每个进程之间,而且也是要在CPU间做到一个负载的均衡。在schedule()之后通过一系列的sys_schedgetset函数来对优先级和cpu的亲和力进行设置。最后的代码则时针对不同的调度方式初始化sched_init()以及相应的运行时队列等。并对进程组进行一系列的设置。

 

 

 

schedule()为例来看看进程调度的过程

1、  初始化变量,cpu为当前进程运行的cpu的编号,rq为当前cpu的运行队列,增加当前CPU静态计数器,prew为当前运行进程,将当前进程上下文切换计数器的值交给switch_count,释放内核锁

2、  禁止本地中断,更新rq时钟,自旋锁锁住rq,清除prevTIF_NEED_RESCHED标志

3、  如果prev不是可运行状态,而且没有在内核态被抢占,从运行队列删除prev。如果他是非阻塞信号,状态为TASK_INTERRUPTIBLE,把该进程的状态设置为TASK_RUNNING,并将其插入运行队列

4、  当运行队列的数量不为0时,进行CPU负载调节

5、  prew设置成运行队列的前一个进程,获取下一个进程

6、  如果prevnext进程为不同的进程,则调用sched_info_switch()切换进程,运行队列的变更计数器加1,将运行队列的当前进程设置为next,选择计时器加1,变更到新的内存管理和新的线程寄存器状态,获得当前cpu ID,将其运行队列设置乘当前运行队列。否则,释放自旋锁

7、  重新获得的当前内核锁不小于0时,则返回第二步执行

8、  在不重新调度的情况下开启优先级

9、  当线程的标记没有TIF_NEED_RESCHED时,返回第一步执行

 

 

 

Linux驱动开发过程中,需要对暴露的接口进行定义,内核就可以按照已有的套路对硬件进行操纵。再回过头来看看Linux进程调度的主函数sched.c中,应该实现的有对sched_class这个模块的调用来达到进程间切换的目的,但是在实际的代码当中,糅进了本该属于sched_rt.csched_cfs.c的东西,代码没有表现出高内聚低耦合的特性。在需要更改进程调度以及添加一个新进程调度方式的时候,sched.c也要进行大刀阔斧的改动。但是Linux进程调度的的种类相对Linux驱动来说就显的很少了,如何使代码更加高效就显得更加重要了,而且在2.6.23之前都是采用的RT调度方式,在2.6.23之后为了增加CFS进程调度而重新设计进程调度的架构就显的不那么重要了,毕竟进程调度的方式相对来说还是很固定的。

 

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