6.s081 xv6-小知识点

Mmap知识点

过程

  1. 当用户调用 mmap 时,会向内核发出系统调用,进入内核态
  2. 内核根据参数(如文件描述符、偏移量、权限等),为当前进程分配一段未使用的虚拟地址(没有映射到任何物理页)。
  3. 内核只是建立了一个 vm_area_struct,登记了这个虚拟地址和文件偏移的映射关系:
  4. 访问这个虚拟地址触发缺页异常
    1. 查找 Page Cache,从磁盘读取文件
    2. 把内容放入 Page Cache,并分配一个物理页
  5. 用户态的虚拟地址对应的页表添加一个页表项 新的虚拟地址指向新分配的物理页

最终,用户空间拿到的是用户空间的虚拟地址,这段地址在访问时仍然会触发页表机制,由 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—->标准输入