操作系统中任务调度的实现

本文详细介绍了在Intel 386 CPU上如何实现任务调度,特别是时间片轮转算法的应用。文章通过分析TSS(任务状态结构)、TSS描述符、任务门等概念,揭示了CPU在任务切换时保存和恢复进程状态的过程。内容包括任务切换的不同场景、CPU的自动更新和只读区域,以及实际操作系统中如何用代码实现这些机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

说起任务调度,我想我们大家都非常熟悉,任何一本操作系统教程,都对此描述得非常详细,不过,他们大多数都是站在理论高度,然而具体到某台实际的机器上,某个实际的操作系统当中,它们具体是怎样用代码去实现的,描述却相对较少。本报告将站在一个编写实际操作系统的角度,去研究一下在Intel 386 CPU结构上怎样去实现任务调度。

本实验的任务调度采用了最简单的时间片轮转算法,因为它的目的并不在于研究采用何种算法调度更有效,而在于研究怎样去调度。我想,在知道了CPU硬件是怎样支持任务调度之后,你可以采用任何一种你喜欢的算法去完成这样的调度。

本实验将同样基于 pyos 系统,你可以在http://purec.binghua.com(纯C论坛)上找到它的全部源代码及资料。

 

任务调度概述

现在的CPU都拥有很强的计算能力,运算速度非常快,然而外部设备却与之速度差距甚远,比如说一个进程需要从磁盘上读取一个文件,那么,此进程需要先通过CPU发送一个读磁盘命令,在磁盘控制器得到这个命令后,磁盘控制器需要启动磁盘驱动器,找到欲读写的磁头、磁道、扇区,然后发出读命令,将数据读到磁盘控制器的缓冲区中,最后再通知CPU到缓冲区中取走数据,我们可以将这一段磁盘驱动器办事的时间称之为数据准备时间,而在这一段数据准备时间内,当前进程因为等待数据而无事可干,进而CPU也无事可干,这样,CPU的效率就显得极低。于是,我们就采用一种更好的策略,先将这个进程调出CPU,而将一个新的进程调入CPU内,当原来进程在等待数据的时候,CPU可以开始执行这个新的进程,当原进程数据准备好后,CPU再将现在执行的这个进程调出去,重新调入原来的进程继续执行,这样CPU就不会出现空等待的情况,CPU的利用率也将因此而大大提高。

于是,现在的CPU都可以同时启动多个进程,不过只有一个进程正在被CPU执行,而其余的进程都因为这样或那样的原因在等待着CPU重新调入执行。通行的做法是,由操作系统给每个进程分配一定的时间片,这个时间片表明了该进程一次可以使用多长时间的CPU,当此进程使用时间到了之后,操作系统就会将其调出CPU,同时将另外一个进程调入CPU让其执行,由于每个进程所分得的时间片都很小,通常是几十个毫秒,因此一秒钟就能让很多进程都执行一两次,这样快的速度,会让人感觉不到切换的进行,与是人们就以为是多个进程在同时运行,其实,这里的同时是宏观上而非微观上的一个观念。

把一个进程调出CPU之后,应当把哪一个进程调入CPU,这就是一种调度算法,通常操作系统会根据这样的一种算法来选定一个将被调入的进程,这是操作系统的事,而CPU并不知道操作系统会怎样选择这个进程,它只知道现在操作系统命令它调入一个新的进程。

要把一个新的进程调入,就需要把原来的进程调出,由于等一会儿说不定还需要回到原来的进程继续运行,因此就必须保存现在的CPU状态,这很像中断处理中的保护现场,那么CPU都需要保护那些信息呢?这些信息又保存在什么地方呢?这个时候,TSS(任务状态结构)就出场了。(注:一般的书上都将其称为“任务状态段”,但我认为这个称呼会与代码段、数据段之类的东东弄混。因此,这里我将其称为“任务状态结构”,其实它本质上就是一块用来存储任务相关信息的空间。)

 

TSS(任务状态结构)的结构

我们先来看看TSS的结构:



上图,就是
TTS的最基本的结构,在它的后面,操作系统还可以另外增加若干字节以存放一些额外的数据,不过CPU只使用最基本的共104字节的空间。从上面的结构中我们可以看见,里面几乎保存了一个进程运行所需要使用的CPU的所有信息,下面,我们就来详细研究下这个结构。

在上图中,已经用三种色彩将上述的TSS结构分成了三部份,对于“未用”部份我们可以不必理会,另外还有两个部份:“CPU自动更新区”及“CPU只读区”,所谓“自动更新”是指当CPU在进行任务切换的时候,会自动将当前任务的相关信息存放到TSS的相应位置中,这样,CPU就保存了当前任务的相关信息。“只读区”是指CPU在任务切换时会从中读取相关信息,但是,在任务被切换出去的时候,不会保存它们,因此,“只读区”的信息是由操作系统在创建任务的时候就指定好的,CPU只是读取而不会去修改它们。

从上图中,我们知道了CPU将当前任务的相关信息保存在什么地方,不过这个TSS实在是太大了!它不可能放在CPU中,而只能被放在内存中,因此我们还需要一个指针只向内存中的TSS,这样CPU就可以通过这个指针找到相应的TSS了,这样的指针有两种,我们分别将其称为“TSS描述符”和“任务门”。

 

“TSS 描述符”及“任务门”的结构与用途

下面我们还是先来看看“TSS描述符”的结构:



上图就是“
TSS描述符”结构,从图中我们可以看见,它给出了一个TSS所在的内存位置以及TSS的大小。这里需要注意的是,从前面的TSS基本结构图中我们可以知道一个TSS基本结构最小不能小于104字节,因此,这里的TSS的大小限制最小是103TSS的最小结构的大小 104 – 1)。另外还要特别引起注意的就是图中的“B”位,这一标志位用来标志一个任务是否是忙任务。如果B位被清零,那么我们就说这个任务是一个“可用任务”,如果B位被置1,我们说这个任务是一个“忙任务”,所谓“忙任务”是指它正在被运行,或者它是一个被任务链链接起来的任务,明白“B”位的用处在实际的编程序非常重要,但在这里不打算详加描述,把详细的描述留给下面的文字完成。

从上图我们可以看出,一个“TSS描述符”指代了一个TSS结构,按理来说,这已经完全足够使用了,但是用于Intel允许在中断的时候也可以进行任务切换,这样,我们就可以把中断处理程序作为一个专门的任务,然而,中断描述符表中存放的只能是门描述符,而上面的“TSS描述符”并不是一种门描述符,因此,它不能被放在中断描述符表中,于是Intel又定义了一种“任务门”,它其实指向的是一个“TSS描述符”,但由于它是一种门描述符,因此,它可以被放在中断描述符表中,这样当发生中断的时候,CPU通过中断号查询中断描述符表,得到相应的门描述符,如果发现它是一个“任务门”,则通过它找到相应的“TSS描述符”,再通过相应的“TSS描述符”找到相应的“TSS结构”。其实,我总觉得定义“任务门”有点多此一举,但Intel已经这样做了,我们也就不得不照办。下面,我们就来看看“任务门”的结构:



上图就是“任务门”的结构,其中被用到的地方极少,
Intel真是浪费啊!P位与DPL位与前面的“TSS描述符”中的相应位的作用是一样的,这里就不多述说了,余下就说说“TSS选择符”吧。

从前面的TSS描述符我们以经知道了,一个“TSS描述符”指代了一个TSS结构,通过它我们可以知道一个TSS结构在内存中的位置。那么我们又怎样得到一个“TSS描述符”的呢?它又是放在什么地方的呢?

在操作系统中,这样的TSS描述符由于会被CPU、中断服务程序、其它进程访问,因此它只能放在“全局描述符表”中(有“关全局描述符表”在《操作系统引导探究》一文中有详细描述)。因此我们需要用一个索引来指出“TSS描述符”在全局描述符表中的位置,这样我们就可以找到相应的“TSS描述符”了,这个索引就被称之为“TSS选择符”,顾名思义,它是用来在“全局描述符表”中选择“TSS描述符”的。

下面,我们通过一个图来看看CPU是怎么进行任务切换的,这个地方比较有趣的是“任务门”与“TSS描述符”都是放在“全局描述符”表中的,并且都需要一个索引指出它们在表中的位置,而这个索引都是一个选择符,分别称为“任务门选择符”与“TSS选择符”。

 

CPU任务切换行为概述



上图就是一个任务切换发生情况的示意图,我们下面就来详细说明一下这个图。

从图上我们可以看出,CPU在下述三种情况下发生了任务切换:

1. 使用了jmpcall指令,而指令的操作符,也即目标地址指向了一个“TSS描述符”或者一个“任务门描述符”。(而这个任务门描述符其实还是指向了一个“TSS描述符”)。

2. 产生了中断,而中断向量指向了中断向量表中的一个“任务门描述符”。

3. 使用了IRET指令,并且在执行这个指令的时候EFLAGS寄存器中的NT位被置1了。

而在这三种情况下发生的任务切换CPU还有不同的动作,下面就让我们来详细的看一看。

1. 如果这个切换是由 jmp 指令引起的,那么,CPU会首先进行特权检查,并检查目标任务的B位(忙位)是否为0,然后CPU将目标任务的B位置为1,把当前任务的B位清零,随后,CPU把当前任务的状态信息压入相应的TSS结构中,并从目标任务的TSS结构中取出相应信息,这样,就完成了一次任务切换。

2. 如果这个切换是由 call 指令或中断引起的,那么,CPU在进行完特权检查后,同样会检查目标任务的B位是否为0

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值