6.s081 xv6-小知识点
Mmap知识点
过程
- 当用户调用
mmap时,会向内核发出系统调用,进入内核态。 - 内核根据参数(如文件描述符、偏移量、权限等),为当前进程分配一段未使用的虚拟地址(没有映射到任何物理页)。
- 内核只是建立了一个
vm_area_struct,登记了这个虚拟地址和文件偏移的映射关系: - 访问这个虚拟地址触发缺页异常
- 查找 Page Cache,从磁盘读取文件
- 把内容放入 Page Cache,并分配一个物理页
- 用户态的虚拟地址对应的页表添加一个页表项 新的虚拟地址指向新分配的物理页
最终,用户空间拿到的是用户空间的虚拟地址,这段地址在访问时仍然会触发页表机制,由 MMU(内存管理单元)完成虚拟地址到物理地址的转换。
Unix/Linux fork-exec 模型
shell执行一个命令是采用先fork再exec
可靠性和隔离性:
- 子进程崩了不影响 shell 进程。
- 子进程的环境变量、打开文件、进程号等可以单独定制。
灵活性:
- 父进程可以决定是否等待子进程结束(同步)或不等待(异步,比如后台任务
&)。
继承机制简洁:
- 子进程继承父进程的资源,通过
fork()一下就复制了整个上下文,再exec()替换执行体即可
fork 子进程来执行命令,是为了保持 shell 自身的运行、提高稳定性与灵活性,并遵循 Unix 的 fork-exec 编程模型;而对于影响当前 shell 状态的内建命令,则直接在 shell 进程中执行
cat命令
cat作用
重定向输出到新文件(覆盖写入)
cat file1.txt > file2.txt
重定向输出到新文件(追加写入)
cat file1.txt >> file2.txt
从标准输入读取内容并保存到文件
cat > newfile.txt
显示整个文件的内容到终端
cat filename.txt (cat < filename.txt )
如果不指定输出,默认标准输出;不指定输入标准输入
代码例子
当执行 cat filename.txt 实际是 cat 0 < filename.txt,
下面是一个简化版的 shell 执行 cat<input.txt 的代码(实际不会这样做):
char *argv[2];
argv[0] = "cat";
### argv[1] = 0;
if(fork() == 0) {
close(0);
open("input.txt", O_RDONLY);
exec("cat", argv);
}
解释
// 关闭标准输入,文件描述符0未使用
close(0);
// 打开 hello.txt ,操作系统会选取一个最小的,也就是未使用的0, 并变成新的标准输入,0指向hello.txt
open("hello.txt", O_RDONLY);
// cat命令会把0输出到1; 也就是从 hello.txt(0) 打印到到标准输出(1) ;==> hello.txt > 控制台
exec("cat");
此时如果0代表hello.txt。那么如何把0恢复成标准输入
int saved_stdin = dup(0); // 保存标准输入的副本
//todo somethine 0已经指向别处,例如hello.txt
dup2(saved_stdin, 0); // 把 saved_stdin 复制回 0
close(saved_stdin); // 关闭副本
先使用dup克隆一个副本描述符(例如3),saved_stdin 选取一个文件描述符指向 标准输入
0—->标准输入 (0,3)—–>标准输入
之后使用dup2,把0指向的hello.txt改变为saved_stdin 所指向的文件
0—->hello.txt ==> (0,3)—->标准输入
最后关闭saved_stdin,close(saved_stdin);
(0,3)—->标准输入 ==>0—->标准输入