首页 > 其他分享 >一个操作系统的设计与实现——第17章 系统交互

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

时间:2023-11-12 10:12:24浏览次数:30  
标签:操作系统 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文件已被删除。

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

标签:操作系统,17,队列,程序,外壳,交互,输入,函数
From: https://www.cnblogs.com/yingyulou/p/17825530.html

相关文章

  • 第117场双周赛-3min签到题,然后做不了一点
     给你两个正整数 n 和 limit 。请你将 n 颗糖果分给 3 位小朋友,确保没有任何小朋友得到超过 limit 颗糖果,请你返回满足此条件下的 总方案数 。 示例1:输入:n=5,limit=2输出:3解释:总共有3种方法分配5颗糖果,且每位小朋友的糖果数不超过2:(1,2,2),(2......
  • 一个操作系统的设计与实现——第3章 保护模式
    实模式下,内存的访问是没有任何限制的,任何程序都能访问和修改任何内存地址,这就导致了实模式下的程序,甚至操作系统自己,都可能自身难保。于是,自8086的下一代产品80286起,保护模式诞生了;进一步的,自80386起,32位保护模式诞生了。3.1内存为什么要分段在学习保护模式之前,需要先讨论一个......
  • 一个操作系统的设计与实现——第2章 主引导记录
    2.1BIOS当按下开机键的那一刻,发生了什么呢?这是一个百废待兴的时刻,所有的硬件设备都刚启动,并没有做好准备,甚至连CPU自己都是。此时,就需要一些外力帮助CPU工作起来。具体来说,在CPU刚启动时,其CS:IP被硬件电路设定为f000:fff0。这个地址并非指向内存,而是指向主板的一个非易失性ROM,......
  • 一个操作系统的设计与实现——第1章 什么是操作系统
    1.1引言什么是操作系统呢?有些读者可能会像曾经的笔者一样,认为操作系统是"一种图形界面";在学习了Linux操作系统后,认为操作系统也可以是"一种命令行"。而不同种类,不同版本的操作系统,则是"不同的图形界面",或是"不同的命令行语法"。那么,以Linux操作系统为例,读者是否想过这些问题呢......
  • 一个操作系统的设计与实现——第5章 加载内核
    一直以来,我们都在使用汇编语言对MBR编程,但对于操作系统这样的复杂程序来说,使用汇编语言是比较困难的。本章将实现操作系统内核的加载与进入。5.1读硬盘的实现原理操作系统存储于硬盘中,现在需要将其读出至内存。想要读硬盘,就需要依次进行以下操作:设定读取的扇区数设定起始扇......
  • 一个操作系统的设计与实现——第9章 硬盘驱动
    操作系统应当具备读写硬盘的能力。因此,本章将要实现的是硬盘驱动。硬盘驱动由两个函数构成:读硬盘函数与写硬盘函数。9.1读硬盘想要读硬盘,就需要提供以下三个信息:起始扇区号读取的扇区数数据存储的地址需要注意的是:读取的扇区数只能是一个8字节的整数。由于读硬盘需要使......
  • 一个操作系统的设计与实现——第8章 内存管理系统
    计算机上的任何程序,包括操作系统自己,都需要使用内存。因此,操作系统需要实现内存管理系统,以进行内存的分配和回收。在我们的操作系统中,内存管理系统由两部分组成:页分配器与页回收器。本章将实现这两个部分。8.1从虚拟地址到物理地址回顾CPU对内存地址的转换过程:使用段寄存器......
  • 一个操作系统的设计与实现——第7章 中断
    7.1什么是中断中断是一种能够随时打断CPU正常工作的机制。这句话看着挺别扭的,CPU工作的好好的,为什么要"随时打断"它?这是因为,CPU需要为诸多外部设备提供服务,以键盘为例,当键盘上的键被按下时,CPU需要对此做出响应和处理,如果不能及时响应,我们会说:"电脑很卡";如果一直都不能响应,我们会......
  • 一个操作系统的设计与实现——第6章 显卡驱动
    进入内核以后,应该做些什么呢?本章将实现一个最容易看到效果的模块:显卡驱动。6.1什么是驱动驱动这个词听起来很高大上,但实际上很简单,就是硬件的接口函数。在软件工程中,可以使用接口封装和简化设计,硬件也是一样。例如:想要读硬盘,需要很多指令设定好几个端口,然后等待硬盘就绪,最后才......
  • 一个操作系统的设计与实现——第12章 任务(三):3特权级任务
    特权级是保护模式的核心概念之一,但我们的操作系统一直没有引入这个概念。这是因为,特权级只有在3特权级任务存在时才有意义。本章将要实现的是3特权级任务的加载与任务切换。12.1特权级12.1.1特权级的功能特权级(PrivilegeLevel),是保护模式中用于限制任务权限的机制。特权级有4......