linux0.11学习之schedule

在一个操作系统中,最重要的部分就是任务调度,linux的0.11版本的任务调度函数比较简单,所以学习任务调度的原理非常适用。

下面我们贴出来schedule函数的代码。

  1
  2 /*
  3  *  'schedule()' is the scheduler function. This is GOOD CODE! There
  4  * probably won't be any reason to change this, as it should work well
  5  * in all circumstances (ie gives IO-bound processes good response etc).
  6  * The one thing you might take a look at is the signal-handler code here.
  7  *
  8  *   NOTE!!  Task 0 is the 'idle' task, which gets called when no other
  9  * tasks can run. It can not be killed, and it cannot sleep. The 'state'
 10  * information in task[0] is never used.
 11  */
 12 void schedule(void)
 13 {
 14     int i,next,c;
 15     struct task_struct ** p;
 16
 17 /* check alarm, wake up any interruptible tasks that have got a signal */
 18
 19     for(p = &LAST_TASK ; p > &FIRST_TASK ; --p)
 20         if (*p) {
 21             if ((*p)->alarm && (*p)->alarm < jiffies) {
 22                     (*p)->signal |= (1<<(SIGALRM-1));
 23                     (*p)->alarm = 0;
 24                 }
 25             if (((*p)->signal & ~(_BLOCKABLE & (*p)->blocked)) &&
 26             (*p)->state==TASK_INTERRUPTIBLE)
 27                 (*p)->state=TASK_RUNNING;
 28         }
 29
 30 /* this is the scheduler proper: */
 31
 32     while (1) {
 33         c = -1;
 34         next = 0;
 35         i = NR_TASKS;
 36         p = &task[NR_TASKS];
 37         while (--i) {
 38             if (!*--p)
 39                 continue;
 40             if ((*p)->state == TASK_RUNNING && (*p)->counter > c)
 41                 c = (*p)->counter, next = i;
 42         }
 43         if (c) break;
 44         for(p = &LAST_TASK ; p > &FIRST_TASK ; --p)
 45             if (*p)
 46                 (*p)->counter = ((*p)->counter >> 1) +
 47                         (*p)->priority;
 48     }
 49     switch_to(next);
 50 }

从代码注释中,我们可以看到linus本人对这段代码是比较推崇的。这段代码可以运行在任何边界,没有理由修改这段代码。有一点需要注意的是信号处理的代码。任务是一个空闲任务,只有在其他任务没有运行时该空闲任务才会被运行。空闲任务不能 被杀死,也不能睡眠。它的tcb即task[0].state,任务状态信息从来不用的。

接下来我们来分析代码。

14,15行定义了一些变量,要说明的是p 这是一个双重指针,双重针指向的类型是任务数据块.数据块里面存放着一个任务的所有信息。

19-28行的代码作用是进行的报警定时值,唤醒任何已经得到信号的可中断任务。



19行开始for循环从最后一个任务开始向前开始遍历所有的任务。

20行判断该任务是否存在,不存在则跳过。

21行判断如果设置过该任务的定时值,且该定时值已经过期则,在信号位图中置位SIGALRM,并清alarm.

要说明的一点是jiffies变量是系统开机开始算起的计时数  10ms/滴答

25.26行如果信号位图中除了被阻塞的信号外还有其它信号,并且任务处于可中断状态,则任务置位就绪态。 ~(_BLOCKABLE & (*p)->blocked)为忽略阻塞信号。

32到48行是调度程序中主要的部分。

先对几个变量进行说明。

(*p)->counter 表示 任务状态的剩余滴答计数。

i表示任务标号,p表示任务数组的地址。

c和next用来保存(*p)->counter和i

这里需要对i和p进行说明。初始

i = NR_TASKS;

p =&task[NR_TASKS]

这两个都是无效值,因为NR_TASKS,用宏定义为64,也就是最多运行64个任务。但因为有任务0,所以任务数只能从0-63.


所以在37,38行判断前对i和p都进行了前减减操作。

39行也是为了判断任务存在,不存在的任务跳过。

40和41行是为了找到当前所有任务中即处于就绪态,且剩余的滴答计时最多的任务。

43行如果找到当前所有任务中即处于就绪态,且剩余的滴答计时最多的任务。跳出循环到49行进行任务切换。

如果当前就绪的所有任务的剩余的滴答数都为0,则重新为所有任务都分配滴答数。

45行为跳过不存在的任务。

46.47行为任务重新分配滴答数。

(*p)->counter = ((*p)->counter >> 1) +  (*p)->priority;

算法为counter = counter/2 + priority

44到48行是为所有的任务都重新分配滴答数。因为之前40行判断的时候可能处于非就绪状态的任务滴答数可能不为0,所以本次分配要对那些在40行判断非就绪状态的任务的滴答数加上之前剩余的一半 再加上自己的优先级。

此时系统中就绪态的任务的滴答数已经重新分配,所以循环回32行,可以重新找到就绪态的最大滴答数的任务。

然后在43行通过break退出循环,执行任务切换。


带中文注释可成功编译运行的Linux0.11+Bochs2.62实验环境说明 此注释以网上获得的“linux带中文注释的0.11版本”为基础,对照赵炯博士《Linux内核完全注释(0.11) 》V3.0版(http://oldlinux.org/download/clk011c-3.0.pdf)编辑而成。作为对赵博士感谢,以及对Linux初学者的回馈,特发布在CSDN上。 此注释可以在http://oldlinux.org/Linux.old/bochs/提供的Linux-0.11-devel-XXXXXX实验环境下正确编译成功,使用:"make disk"命令重启Bochs虚拟机后,新编译源码直接生效,便于学习者直接阅读源码,直接进行实验。 注意事项: 1、为了使注释版与实验环境上的Linux0.11内核保持一致,达到对应文件可以互换的目的,与Linux0.11原始版本相比,加入了15个系统调用函数(参见include/Linux/sys.h第78-92行。赵博士原书没有这部分注释,我不敢班门弄斧),其它相关的文件加入了相应的定义。新加入的代码只有函数体定义,没有具体实现,对其它原始代码没有改变、没有影响。 2、键盘定义改成了美式键盘(原始代码中是芬兰键盘,会导致个别键出问题,调试的时候我曾被迷糊了好久,以为自己把程序搞乱了)。 3、把网上VC版的注释统一改成了 “/* */” 格式的注释。经测试,在Linux0.11实验环境中(gcc1.40),只有标准C注释语法可以正常编译。 4、由于《Linux内核完全注释(0.11) 》原书版本更新的原因,注释中提到的图、表可能与V3.0版书中不一致。 5、由于代码中加入注释,代码行号发生变化,注释中提到的代码行号会出现不一致,建议对照3.0版查询对应内容。 6、实验方法:请先安装附带的Bochs2.62版安装包,双击Test.bxrc即可启动实验系统,执行命令:sh t,即可完成对linuxcn的编译。 7、linux目录中是此实验系统中/usr/src/linux提取出来的不含中文注释的linux0.11源码(此版本比原始的0.11版多15个系统调用函数),linuxcn是加入了中文注释的源码。 8、diskb.img是实验系统与Windows环境下进行文件交换的1.44M软盘映像,执行脚本命令"sh t"时会自动从此映像中读取linux.tar、linuxcn.tar包,解包并编译,编译结果在:/usr/root/zw/linuxcn目录下。为了方便文件交换,建议使用7zip为压缩/解压缩工具(7zip可以直接生成tar包),用WinImage实现Windows环境与软件映像交换文件。 9、实验系统下 .profile中加入了几个命令,请读者注意。 10、若实验环境的启动盘被破坏,请用压缩包中的bootimage-0.11-hd覆盖对应文件即可。 11、若实验环境的要命文件系统被破坏,请用压缩包中的hdc-0.11-new.img覆盖对应文件即可。 2014-5-4 cyfx2288
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

奔跑的小刺猬

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值