2. 所有进程构成的双向链表
进程描述符中有成员变量 struct list_head tasks。可以构成双向链表。
在进程调度是利用该链表来查找进程显然是不合理的,于是linux内核有构建了新的数据结构提高调度效率。
3. 执行态进程组成的运行队列
Linux2.6内核采用了新的调度机制(与2.4相比),实现了O(1)复杂度。采用了新的运行队列实现了新的调度算法。内核为每个处理器都设置了一个运行队列。
O(1)复杂度的调度算法的核心数据结构是—-运行队列 struct runqueue;(定义在/kernel/sched.c)
其中有一个实现O(1)复杂度的关键成员变量优先级数组: prio_array_t *active, *expired, arrays[2];active 和 expired 分别指向活动和超时的优先级数组,arrays[2]用于存储着两个优先级数组。每个进程在时间片用完后,根据优先级重新分配时间片,优先级会在每次进程切换时重新计算,然后将其移到expried优先级数组中,当active数组中没有活动进程是,交换两个指针指向的数组。这是linux2.6实现实现O(1)复杂度调度算法的基础。
优先级数组定义如下:(定义在/kernel/sched.c)
struct prio_array { unsigned int nr_active;//该优先级数组中可运行的进程数 unsigned long bitmap[BITMAP_SIZE];//优先级位图 struct list_head queue[MAX_PRIO];//可执行进程队列,为每一个优先级设置一个可执行进程队列};大概过程如下:当进程被创建并投入运行时,首先将进程插入到对应的可执行队列的对尾,然后根据进程的优先级设置对应的优先级位图,例如优先级为N,就设置优先级位图的第N位,表示该优先级进程队列不为空。当调度时,首先获取优先级位图中第一个不为0的bit为的序号,该序号指明了当前最高优先级进程所在的可执行队列,相应的可执行队列的第一个进程也就是“合适”的进程。大致如下:array = rq->active; idx = sched_find_first_bit( array->bitmap );
queue = array->queue + idx;
next = list_entry( queue->next, task_t, run_list);//next指向“合适“的进程。