一个操作系统的设计与实现——第17章 系统交互

操作系统最终是供用户使用的,所以其需要具备与用户交互的能力,交互方式可以是命令行,图形界面,甚至是触摸屏,语音,实体按钮等。本章将要实现的是系统交互。

17.1 外壳程序

我们的操作系统使用的是基于命令行的交互模式。实现此功能的模块被称为外壳(Shell)程序。

事实上,上一章的Test.c已经是一个简单的外壳程序了,它唯一的功能是:读取命令行输入,然后将其打印。因此,如果对命令行输入进行解析,根据其内容调用各种操作系统内核函数,就能得到一个具有实用价值的外壳程序。

我们的外壳程序支持以下四种命令:

  1. l命令;调用fsList函数
  2. c 文件名 起始扇区号 扇区数命令;调用fsCreate函数
  3. d 文件名命令。调用fsDelete函数
  4. r 文件名命令。调用fsLoad函数

如果命令行输入不是上述命令中的一种,则打印输入的字符串。

17.2 外壳程序等待

我们的外壳程序支持的四个命令中,前三个都很容易实现,但第四个是有问题的。具体来说,如果直接调用fsLoad函数,新任务就会和外壳程序同时处于任务队列中。这并非一个错误,后台运行模式正是基于此原理实现的。但我们的操作系统并不支持后台运行模式,当外壳程序加载一个任务后,其需要等待这个任务退出后才能继续执行。

想要让一个任务等待,就需要一个专用的队列。这项技术在实现IO队列时已经使用过了。具体来说,想要让外壳程序等待被加载任务的结束,就需要实现以下功能:

  1. 创建一个新的任务队列供外壳程序使用。不妨称之为外壳队列
  2. fsLoad函数调用后,立即发起任务切换。并将发起者,即外壳程序添加到外壳队列中
  3. 当任务退出时,从外壳队列中取出外壳程序,并将其重新添加到任务队列

17.3 系统交互的实现

17.3.1 外壳程序等待的实现

请看本章代码17/Task.h

第21行,声明了外部链接的外壳队列shellQueue

接下来,请看本章代码17/Task.hpp

第14行,定义了外壳程序专用的外壳队列shellQueue

第54行,在taskInit函数中添加对外壳队列的初始化。

第217~219行,当3特权级任务加载完成后,将当前任务,即外壳程序的TCB中的taskQueue数据成员设定为外壳队列,然后立即发起任务切换。此时,新任务已经位于任务队列中,而外壳程序将在外壳队列上等待。

接下来,请看本章代码17/Int.s

第12行,声明了外部链接的外壳队列shellQueue

第194行,将push taskQueue修改为push shellQueue。任务退出时,应从外壳队列中将正在等待的外壳程序取出,并重新添加到任务队列。这行代码与17/Task.hpp中的第217~219行对应。

第198行,将外壳程序的TCB中的taskQueue数据成员重新恢复为任务队列。

17.3.2 外壳程序的实现

请看本章代码17/Util.h

第21~22行,声明了本章新增的两个函数。

接下来,请看本章代码17/Util.hpp

isalnumisdigitnextStrnextNum是本章新增的四个辅助函数。isalnumisdigit函数与C语言标准库的同名函数等价;nextStr函数用于取得给定字符串的下一个单词,其相当于C语言标准库的strtok函数的简化版;nextNum函数用于取得给定字符串的下一个整数,其相当于nextStr函数与STL的stoi函数的结合。

接下来,请看本章代码17/Shell.h

第3行,声明了shellInit函数。

接下来,请看本章代码17/Shell.hpp

__parseCmd函数用于解析命令行输入。

第12~15行,解析l命令,并调用fsList函数。

第16~25行,解析c 文件名 起始扇区号 扇区数命令,并调用fsCreate函数。

第26~31行,解析d 文件名命令,并调用fsDelete函数。

第32~37行,解析r 文件名命令,并调用fsLoad函数。

第38~41行,如果命令行输入不属于上述情况,则打印输入的字符串。

shell函数实现的是外壳程序。

第47行,定义输入的字符串。

第49~54行,在循环中不断进行以下三个操作:

  1. 打印命令提示符
  2. 读取命令行输入
  3. 调用__parseCmd函数,以解析输入的字符串

shellInit函数用于加载外壳程序。外壳程序调用了文件系统以及Util.hpp中的函数,这些函数都是仅限0特权级使用的,所以外壳程序应加载为一个0特权级任务。读者也可以将外壳程序加载为一个3特权级任务,这就需要将其使用的所有函数都安装成系统调用,或在3特权级下以函数库的形式实现。

接下来,请看本章代码17/Kernel.c

第21行,调用shellInit函数,完成外壳程序的初始化。

17.4 测试

本章使用的测试任务为17/Test.c。其先读取字符串,再打印读取到的字符串。

启动bochs后,可以发现命令行已经开始工作。

在命令行中输入c test 1000 20命令,再输入l命令,可以发现test文件已经安装完毕。

在命令行中输入r test命令,可以发现test程序已经开始运行,命令行正在等待用户输入,而此时的外壳程序处于等待状态。输入任意字符串后回车,可以发现test程序在打印输入字符串后结束,外壳程序重新开始运行。

在命令行中输入d test命令,再输入l命令,可以发现test文件已被删除。

我们的操作系统到这里就全部实现完成了。

posted @ 2023-11-12 09:55  樱雨楼  阅读(17)  评论(0编辑  收藏  举报