系统调用与环境的封装

系统调用与环境的封装

2024 南京大学《操作系统:设计与实现》
系统调用与环境的封装

输入/输出

Standard I/O: stdio.h

  • FILE * 背后其实是一个文件描述符
  • 我们可以用 gdb 查看具体的 FILE *
    • 例如 stdout
  • 封装了文件描述符上的系统调用 (fseek, fgetpos, ftell, feof, ...)

The printf() family

  • 这些代码理应没有 “code clones”
printf("x = %d\n", 1);
fprintf(stdout, "x = %d\n", 1);
snprintf(buf, sizeof(buf), "x = %d\n", 1);
2024 南京大学《操作系统:设计与实现》
系统调用与环境的封装

popen 和 pclose

我们在游戏修改器中使用了它

  • 一个设计有历史包袱和缺陷的 API
    • Since a pipe is by definition unidirectional, the type argument may specify only reading or writing, not both; the resulting stream is correspondingly read-only or write-only.

为什么我们要用现代编程语言?

let checksum = {
  Exec::shell("find . -type f")
    | Exec::cmd("sort") | Exec::cmd("sha1sum")
}.capture()?.stdout_str();  // ()? returns "std::nullopt"
2024 南京大学《操作系统:设计与实现》
系统调用与环境的封装

err, error, perror

所有 API 都可能失败

$ gcc nonexist.c
gcc: error: nonexist.c: No such file or directory

反复出现的 “No such file or directory”

  • 这不是巧合!
    • 我们也可以 “山寨” 出同样的效果
  • Quiz: errno 是进程共享还是线程独享?
    • 线程有一些我们 “看不到” 的开销:ucontext, errno, ...
2024 南京大学《操作系统:设计与实现》
系统调用与环境的封装

environ (7)

int main(argc, char *argv[], char *envp[]);

envp: execve() 传递给进程的 “环境”

  • 问题来了:全局变量 environ 是谁赋值的?
    • 是时候请出我们的老朋友 watch point 了
  • RTFM: System V ABI
    • p33
    • Figure 3.9 Initial Process Stack
      • 操作系统有一个 “初始状态”
      • libc 调用 main 前还会继续初始化这个 “初始状态”
2024 南京大学《操作系统:设计与实现》