[修改回复]
删除回复
插入表情:
宋体
楷体
幼圆
黑体
隶书
华文行楷
方正舒体
Arial
Arial Black
Arial Narrow
Century Gothic
Comic Sans MS
#0000FF
#8A2BE2
#DEB887
#5F9EA0
#7FFF00
#000000
#D2691E
#FF7F50
#FF0000
#DC143C
#99ccff
字体颜色
#FFF8DC
#00FFFF
#EE82EE
#F5DEB3
#FFFFFF
#F5F5F5
#FFFF00
#9ACD32
使用帮助
二、数据结构 1. 进程优先级的划分 Kernel 2.6将进程优先级作了以下规定: 进程优先级范围是从0 ~ MAX_PRIO-1,其中实时进程的优先级的范围是0 ~ MAX_RT_PRIO -1,普通进程的优先级是MAX_RT_PRIO ~ MAX_PRIO-1。数值越小优先级越高。 2. 就绪队列runqueue(kernel/sched.c) struct runqueue是2.6调度器中一个非常重要的数据结构,它主要用于存放每个CPU 的就绪队列信息。限于篇幅,这里只介绍其中相对重要的部分: (1) prio_array_t *active, *expired, arrays[2] 这是runqueue中最重要的部分。每个CPU的就绪队列都是一个数组,按照时间片是否 用完将就绪队列分为两个部分,分别用指针active和expired来指向数组的两个下标 。prio_array_t的结构如下: struct prio_array { int nr_active; /*本进程组中进程个数*/ struct list_head queue[MAX_PRIO]; /*每个优先级的进程队列*/ unsigned long bitmap[BITMAP_SIZE]; /*上述进程队列的索引位图*/ }; 数组queue[MAX_PRIO]里面存放的是优先级为i(MAX_PRIO>i>=0)的进程队列的链表 头,即task_struct::runlist(通过runnlist即可找到task_struct)。 那么调度器在执行调度的任务时是怎么找到优先级最高的进程呢? 在结构体struct prio_array中有一个重要的数据unsigned long bitmap[BITMAP_SIZE ],这个数据是用来作为进程队列queue[MAX_PRIO]的索引位图,bitmap的每一位(bit )都与queue[i]对应。当queue[i]的进程队列不为空时,bitmap的相应位就为1;否 则就为0。这样我们只需要通过汇编指令从进程优先级由高到低的方向找到第一个为 1的位置idx即为当前就绪队列中最高的优先级(函数sched_find_first_bit()就是用 来完成这一工作的),那么queue[i]->next就是我们要找的task_struct::runlist。 当一个普通进程的时间片用完以后将重新计算进程的时间片和优先级,将该进程从active array中删除,添加到expired array中相应优先级的进程队列中。当active array 中没有进程时,则将active和expired指针调换一下就完成了切换工作。而在2.4内核 中重新计算时间片是在所有就绪进程的时间片都用完以后才统一进行的,因而进程时 间片的计算非常耗时,而在2.6中计算时间片是分散的,而且通过以上的方法来实现 时间片的轮转,这也是2.6调度器一个亮点。 另外,程序将struct runqueue定义在sched.c里面而没有定义在sched.h里面是为了 让抽象调度器部分的代码,使得内核的其他部分使用调度器提供的接口即可。 (2) spinlock_t lock runqueue的自旋锁,当对runqueue进行操作的时候,需要对其加锁。由于每个CPU都 有一个runqueue,这样会大大减少竞争的机会。 (3) task_t *curr CPU当前运行的进程。 在程序中还有一个全局变量current也是CPU当前运行的进程,它在通常情况下和runqueue 的curr指针是相同的,但是当调度器进行调度的时,如果已经找到最高优先级的进程 ,则此时做rq->curr = next;可见在进行任务切换之前,rq->curr和current的值是 不同的。当唤醒一个进程的时候,很明显将唤醒进程与rq->curr的优先级进行比较更 有意义。 (4) unsigned long expired_timestamp 此变量是用来记录active array中最早用完时间片的时间(赋值jiffies)。因此, 用这个量就可以记录expired array中等时间最长的进程的等待时间。这个值的主要 用处是用于宏EXPIRED_STARVING()(这个宏主要是用来判断expired array中的进程 是否已经等待了足够长的时间,详见"进程调度的生与死"一节中"scheduler_tick() "函数的介绍)。 (5) unsigned long nr_running, nr_switches, nr_uninterruptible, timestamp_last_tick 用来记录该CPU进程相关数据。具体作用如下 用来记录该CPU进程相关数据。具体作用如下 nr_running 记录该CPU上就绪进程总数,是active array和expired array进程总数和 nr_switches 记录该CPU运行以来发生的进程切换次数 nr_uninterruptible 记录该CPU不可中断状态进程的个数 timestamp_last_tick 记录就绪进程队列上次发生调度的时间,用于负载均衡 (6) struct list_head migration_queue 这个是存放希望迁移到其他CPU上的进程队列,实际迁移的数据类型是migration_req_t ,这里是通过将migration_req_t::list连接起来。详见"负载均衡"中"push"一节。
不能为空
不能含有 ` 字符,字数8000以内
(CTRL+ENTER提交)
关闭窗口