今天我们通过一个实例
来介绍系统调用的使用和实现
在这里我们通常从应用程序的写法上来说这个事
我们说我想写一个程序
能够把一个文件的内容复制出来
写到另一个文件里头改一个名字
这个地方是我把这件事情展开之后
我写程序会是什么样的
首先我会在屏幕上输出一个提示
要求用户输入
你要读的那个文件的名字
然后等待键盘输入
接下来 我会提示用户
在屏幕上给出提示说让它输入输出文件的名字
等待并接受键盘的输入
等到这两个信息都有了
然后说我们就试图去打开相应的文件
首先去打开输入文件
如果输入文件在你的文件系统当中有
那这是成立的 如果说文件不存在
这个时候肯定出错了因为我要复制的源没有了
接下来说我去看看创建输出文件
如果说你有这个文件
这个时候我会把原来东西覆盖掉
这是不对的 这个时候如果文件存在
这个时候我出错退出 这几步都做完了之后
那我就确认我的输入文件是存在的
输出文件是没有的
然后开始循环从文件当中读数据写到输出文件
从输入文件当中读数据
从输出文件当中把数据写到输出文件中
那为什么会在这做循环
有可能这个文件很小我一次就搞完了
如果这个文很大我可能会循环若干次
等所有这些都做完
那么这个时候我关闭输出文件和输入文件
然后屏幕上提示我整个事情做完
整个程序正常退出 那这是我想写的程序
对于这个程序来说
我会用到哪些系统调用
我们会有键盘的输入 有屏幕的输出
有文件的输入和输出
实际上在操作系统内核里
它这个实现键盘 屏幕和文件
都视为是文件系统里的
只是说键盘和屏幕作为特殊的文件来使用
那么在这里头涉及到的系统调用是
open close还有一个应该是create
然后再有一个write read
有了这几个系统调用之后
那么我这件事情在上边
用我的函数库里内容就可以完成
具体怎么来做 我们看到要想在应用程序写
那应用程序会使用到一个库函数read
这和我们用到其他函数是一样的
在我们ucore有这样一个头文件
告诉你他格式什么样子
然后这里头你需要知道这里的参数是什么意思
你读写的文件 你读出来的数据放在什么地方
缓冲区域头指针
然后这个缓冲区域并不是无限大的
它的最大长度你不能超过这个长度
然后我从里头读数据往里放
那我实际读出来的时候
有可能比这短
因为我实际文件里可能没有这么多数据
如果说我实际数据比这个缓冲区大怎么办
这个时候最多读出来是缓冲区长度
因为在多就缓冲区溢出了
然后读完之后返回值 这个地方有个返回值
返回值是你的长度 你在使用的时候怎么做
你打开文件 把这三个参数填上去
返回来的时候
返回的结果就是你实际的程度
这是你在用的时候
对于我们系统的实现来讲
在编译程序的时候
你的应用程序用到相应的库函数
这个库里头在编译系统调用的内容的时候
它就会前面准参数
实际上这段都会往堆栈压栈
压占完之后最后有函数调用
而这个函数调用最后都转到我有一个
你说这不是系统调用 是的
这是一个函数调用
这个函数调用所有的系统调用
它都是通过一个宏展开形成相应的函数
实际上在这里有一段汇编
大家注意这段汇编有可能你现在还不能完全看懂
那你需要值得这个int
是我们前面说到系统调用的指令
后面i实际上是你系统调用的中段向量编号
后面num实际就是系统调用read系统调用编号
然后后面是相应的参数
这些填完之后
实际上最后你在的执行应用程序
执行到这个地方 到这里来的时候
它就会转成系统调用进到内核里去
接下来我们操作系统里是如何实现系统调用read
首先我们刚才说在用户态一个int进到内核里来之后
这实际上是一个软中段
所有这些都会到你最开始一段汇编程序叫alltraps
在这里会获取到中段所需要的
相关信息组成的数据结构
这个时候实际上TF数据结构
那么在这里头我们注意到其中有一条
是其中的中段向量
那么在这里是系统调用对应中段向量
然后依据这个那么在trap函数里头
它就会转到我们系统调用这个函数里头
在这个函数里头它会读其中的EAX
实际上就是你的系统调用编号
这个系统调用编号会看到它是等于read
等于这个实际上相当于这个时候
我们知道进来是系统调用
并且这个系统调用调用是哪个功能
我们还缺什么
我们还缺它参数
这些参数就会转到相应的系统调用实现里头
这个实现里负责去堆占里头SP
获取相应我们当时填进堆占里头那三个参数
这个文件 缓冲区 头指针
然后缓冲区长度 有了这三个之后
实际上这个时候就相当于
已经从用户态转到内核态
如果说我是一个函数调用的话
这个时候就已经转过来
我在继续做相应函数实现就可以了
这个时候我们就看到最后它到sysfile read
这个函数里头去完成相应的文件读取功能
这个文件读取就是直接操作底下的驱动程序
在往下 等到它最后返回的时候
ok 那这个时候我们到这trapret
在这里头我们去看这类代码最后会有ireturn
这个return会把相应的返回值的长度
读到内容长度返回给用户态
整个实现就全部完成
那接下来我们会去看看实际的系统里的代码是什么样子的