2.1实现原理
想要在DOS环境下实现多任务调度,必须使每个任务具有自己的堆栈。首先,栈用来实现任务切换,其次,它用来存贮任务的局部变量。
任务的切换是通过调用一个子程序来实现的,该子程序将堆栈指针由原来指向老任务的堆栈置为指向新任务的堆栈。程序返回时,新的任务指令指针(IP)就从栈中弹出。新任务就开始自动开始执行。
这个负责调度的子程序是通过时钟中断来定期触发的。当产生时钟中断时,需要做两件事情。首先,将标志(Flags)寄存器的内容压入栈中,其次,紧跟在指令指针(IP)之后,将CS(代码段)也压入栈中。最后,将中断服务子程序的段地址装入CS寄存器中,将偏址装入IP寄存器中.这样可以使ISR开始运行.中断返回时,CS,IP和Flags寄存器的内容自动弹出。为了实现任务的调度,新的时钟中断服务函数要完成两项工作。首先,它将除了栈指针(SP)和栈段(SS)寄存器之外的所有寄存器的值都存到栈中。(SP和SS的值存在另外的位置)。其次,它改变SS和SP寄存器的值,使它们指向另一个任务的堆栈。因此,当ISR返回时,新的任务的堆栈被弹出到各寄存器中,这使得机器的状态是针对新的任务的。由于IP中也是弹出的寄存器的值,因此新任务就开始执行。
在任务运行前,它必须按一定方式使堆栈初始化,这样使得当第一个时间片到来时,从栈中弹出的值能够使该任务从头开始运行。因此,任务的堆栈必须初始化并存放正确的寄存器值,同时指令指针也必须指向程序中的第一条指令。
2.2调度内核实现所用到的数据结构
interrupt 类型
当说明一个函数为interrupt类型时,它告诉编译器自动保存所有寄存器(sp和ss除外)的值,并且IRET指令终止该函数。每当进入到interrupt函数时,执行下列指令:
push ax, push bx, push cx,
push dx, push es, push ds
push si, push di, push bp
发生中断时,CPU自动将Flags,cs和IP寄存器压栈。因此,在interrupt函数入口处,堆栈如图2.2.1.2所示。我们将利用interrupt函数的栈的安排方式对要执行的任务的堆栈进行初始化。
Bp<-top of stack
DI
SI
DS
ES
文章来源于领测软件测试网 https://www.ltesting.net/