在O(n)调度器中,“运行队列”实际上只是个逻辑概念,内核只是用一个列表将就绪任务串起来了而已,并没有单独定义一个数据结构。O(1)调度器的实现中专门定义了结构体 struct runqueue
来对各种信息进行封装:
/* file: kernel/sched.c */
struct runqueue {
spinlock_t lock;
unsigned long nr_running;
#ifdef CONFIG_SMP
unsigned long cpu_load;
#endif
unsigned long long nr_switches;
unsigned long nr_uninterruptible;
unsigned long expired_timestamp;
unsigned long long timestamp_last_tick;
task_t *curr, *idle;
struct mm_struct *prev_mm;
prio_array_t *active, *expired, arrays[2];
int best_expired_prio;
atomic_t nr_iowait;
#ifdef CONFIG_SMP
/* SMP 下用于负载均衡的字段 */
struct sched_domain *sd;
/* For active balancing */
int active_balance;
int push_cpu;
task_t *migration_thread;
struct list_head migration_queue;
#endif
#ifdef CONFIG_SCHEDSTATS
/* 删掉调度器的信息统计字段*/
#endif
};
/* file: kernel/sched.c */
static DEFINE_PER_CPU(struct runqueue, runqueues);
/* file: kernel/sched.c */
struct prio_array {
unsigned int nr_active;
unsigned long bitmap[BITMAP_SIZE];
struct list_head queue[MAX_PRIO];
};
asmlinkage void __sched schedule(void) {
task_t *prev, *next;
runqueue_t *rq;
prio_array_t *array;
struct list_head *queue;
unsigned long long now;
unsigned long run_time;
int cpu, idx;
/* 拿到当前CPU的runqueue */
rq = this_rq();
/* 拿到队列中的任务列表,为prio_array_t类型,实际上就是上面讨论过的
* prio_array */
array = rq->active;
/* 从prio_array中找到下一个进程,O(1)复杂度 */
idx = sched_find_first_bit(array->bitmap); /* 找到目标优先级队列的索引 */
/* 通过索引拿到对应的runqueue, 该队列即是当前优先级最高的任务队列 */
queue = array->queue + idx;
/* 从runqueue中取出第一个task, 该task即是下一个应该扔CPU上运行的task */
next = list_entry(queue->next, task_t, run_list);
}