一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第4天,点击查看活动详情。
原文链接 xv6-riscv文档
1.2 I/O与文件描述符(续)
open的第二个参数包含了一系列bits组成的参数来控制open的行为,其可能的值在control头中被定义,分别是O_RDONLY, O_WRONLY, O_RDWR, O_CREATE, 和O_TRUNC,这些控制open打开文件是读、写、读写、创建文件还是将文件变为0长度。
到目前为止为什么fork和exec是分别的系统调用就很明显了:在这两者之间,shell可以重定向子进程的IO而不需要打扰shell的IO。我们可以假设一个混合的forkexec系统调用,但是用这样的系统调用做IO重定向是尴尬的事情。shell需要改变他自己的IO设置在调用forkexec之前;或者forkexec需要携带IO重定向指令做参数,或者至少每一个像cat这样的程序都要被设置做自己的IO重定向。
虽然 fork复制了文件描述符,但每一个文件当前的偏移仍然是在父子进程之间共享的,考虑下面这个例子:
if(fork() == 0) {
write(1, "hello ", 6);
exit(0);
} else {
wait(0);
write(1, "world\n", 6);
}
在程序的结尾,放到文件描述符1上的文件会有数据hello world
,而父进程中的write会从子进程write之后的地方继续写入(因为wait的存在,父进程晚于子进程运行)。这种行为有利于shell顺序指令的顺序输出,像(echo hello; echo world) >output.txt
。
dup系统调用复制一个存在的文件描述符并且返回一个指向相同IO对象的文件描述符。这两个文件描述符共享一个偏移量,就像fork中复制的文件描述符一样。以下是另一种写入helloworld
到文件的方式:
fd = dup(1);
write(1, "hello ", 6);
write(fd, "world\n", 6);
通过一系列fork和dup产生的来自于同一个初始文件描述符两个文件描述符共享同一个偏移量。其他的文件描述符并不共享,即使他们是同一个文件通过open调用得到。dup允许shell实现像下面这样的命令:
ls existing-file non-existing-file > tmp1 2>&1
2>&1
告诉shell文件描述符2是文件描述符1的复制,这样存在的文件或者不存在文件的报错都会在文件tmp1中出现。xv6shell不支持错误文件描述符的IO重定向,但是现在你知道如何实现了。
文件描述符是一个强大的抽象,因为它隐藏了他们连接的细节:进程写入文件描述符1也许是写入到文件、像console一样的设备或者一个管道。
刚结束中期答辩,明天将会优化排版。
感谢阅读~