MIT6.828_HW2_SHELL
Homework: shell
1.预备知识:
1.XV6讲义P7-P14
2.源码中部分常用函数的了解:
3.文件描述符:
在xv6内核中,每个进程都有一张文件描述符表,表项描述了文件的各种信息,一个表项对应一个文件,文件描述符即是文件在表中对应表项的下标,进程通过文件描述符对文件进行读写等各种操作,按照约定,进程一般通过标准输入文件(fd=0)读取数据,对标准输出文件(fd=1)进行写操作,将错误信息输出到标准错误文件(fd=2)上,并且这三个文件描述符默认都是打开状态,通过利用这些约定,使用close,dup,open等函数,重新分配0,1等文件描述符,能够达到实现I/O重定向,管道通信的目的。
2.实现简单的命令(如ls)
parsecmd已经实现了命令解析,我们只要在runcmd中实现case’'的部分即可,调用execv()函数,该函数可能因给定的绝对路径不正确而找不到对应程序,此时修改路径名即可。**
3.实现I/O重定向
对于文件描述符的具体说明在XV6讲义第十页,实现I/O重定向抓住一个要点即可:系统将为打开文件分配编号最小且未被使用的文件描述符。因此要实现重定向,我们可以先关闭标准输入或标准输出文件,释放它们的文件描述符,再打开目标文件,这样标准输入或标准输出的fd就分配给了目标文件。代码如下:
4.管道
要实现ls | sort | uniq | wc这类命令,重点在于如何使得上一个进程/上一条命令的输出变成下一个进程的输入,这就涉及到进程间通信的相关知识,进程间通信最简单最笨拙的方式就是通过文件系统来实现进程间的通讯,但这种方式效率太低,速度太慢(因为要对硬盘直接进行操作),还有一种方式是在OS内核中开辟出一块空间,以供进程通信,管道是一种利用文件系统接口,在OS内部实现的一种进程通信方式,具体解释和样例见xv6讲义第13页,要点有以下:
1.pipe在创建时,会在内核中开辟一块缓冲区,同时会返回两个文件描述符(一个用来读,一个用来写)
2.pipe通过文件接口如read,write等来进行操作
3.pipe不能进行open操作,它是无名管道
管道的通信原理可以参考这位大佬的博客 进程间的通信方式-pipe
代码如下:
特别注意代码图片中红框圈起来的部分,当有进程通过管道读端读数据时,若管道写端的引用计数不为0且管道内所有数据已被读完时,读进程读数据会被阻塞。所以我们在父进程执行wait之前要把管道写端关闭。关闭写端与不关闭写端的对照输出如下图:
在wait之前关闭写端:
情况1:
情况2:
情况1和2都能正常输出:
在wait之后关闭写端:
父进程和子进程都被阻塞: