LINUX调度函数有借鉴于UNIX操作系统,当初LINUS在写作LINUX的时候主要学习了塔嫩鲍姆的《操作系统设计与实现》和《UNIX操作系统设计》这两本书,所以LINUX的很多设计思想均来源于此。本文介绍了LINUX的核心代码,即进程的调度是如何实现的,为了简洁起见,这里删除了一些无关代码。
有别于MINIX,除了LINUX是单内核外,其调度函数也是采取非队列形式的,MINIX把不同运行状态的进程划分成不同的队列,进行移进或者移出,在LINUX中这些队列是不存在的,这样做的所有目的只有一个:保持系统的简单,便于新的开发者快速上手。这也是为什么LINUX这么流行,而MINIX被相对尘封的原因。
笔者正在写一个自己的操作系统,在任务调度中也采取了类似的手法。有兴趣的朋友可以浏览我的web网页:http://jicama.126.com
/*
* 'schedule()' is the scheduler function. It's a very simple and nice
* scheduler: it's not perfect, but certainly works for most things.
* The one thing you might take a look at is the signal-handler code here.
*
* NOTE!! Task 0 is the 'idle' task, which gets called when no other
* tasks can run. It can not be killed, and it cannot sleep. The 'state'
* information in task[0] is never used.
*/
void schedule(void)
{
int i,next,c;
struct task_struct ** p;
/* this is the scheduler proper: */
while (1) {
c = -1; //置初始值,当counter为负数的情况是不被允许的,counter为0的话,表明运行完了属于自己的时间块
next = 0;
i = NR_TASKS; //从尾部开始扫描
p = &task[NR_TASKS];
while (--i) { /*扫描所有的进程*/
/*如果进程项为空的话,表明该资源未被使用,跳过*/
if (!*--p)
continue;
/*只有处于运行态的进程才有这个被调度*/
/*从里面抽取可可运行时间最长的值*/
if ((*p)->state == TASK_RUNNING && (*p)->counter > c){
c = (*p)->counter; /*记录这个进程的可运行的时间块*/
next = i;/*记录这个进程的位置*/
}
}
if (c) break; //这里假设C为0的话,表明该进程刚运行完CPU分配给自己的时间块这个是非常值得考究的地方也是调度设计的奥妙所在
/*下面代码出现的情况只能是所有的counter 都为0,即所有的任务都运行完了属于自己的时间块,这里要做的是重新评估下一轮中,自己能运行多久,而这个值是由priority 决定的,counter= counter/2+ priority,并意图进行衰减,其实这里counter的值都已经为0,对于可运行进程,counter等于priority,但是对于正在睡眠的进程来说,这里的运算增加了他们的优先权,以便在进入运行态后被很快的选取运行,*/
for(p = &LAST_TASK ; p > &FIRST_TASK ; --p)
if (*p)
(*p)->counter = ((*p)->counter >> 1) +
(*p)->priority;
}
switch_to(next); /*进程跳转*/
}
/*时钟中断函数,(截取的代码)*/
void do_timer(long cpl)
{
/*CPL是根据堆栈保存的CS来定的,取其最低的2位来决定进程是处于内核还是用户状态中*/
if (cpl)
current->utime++; /*增加进程在用户态的运行时间*/
else
current->stime++; /*增加进程在内核态的运行时间*/
if ((--current->counter)>0) return; /*当前进程的时间片还没有运行完毕,所以不做调度*/
current->counter=0; /*当前进程的时间片运行完了,所以可能需要执行调度新的程序来运行*/
if (!cpl) return; /*因为调度会引起任务切换,为了保存在内核中的数据,不能在内核态下面执行*/
schedule(); /*所有条件OK,在用户态下面执行调度*/
}
/*较高的NICE值会降低进程调度的优先权*/
int sys_nice(long increment)
{
//因为只能降低,所以increment的值不能为负
//需要超级用户才能执行该操作
if (increment < 0 && !suser())
return -EPERM;
//框定priority的值最小必须是1,否则(为0的话)程序将永远得不到调度(参看调度函数)
if (increment > current->priority)
increment = current->priority-1;
current->priority -= increment;
return 0;
}