常用的系统接口
系统调用 | 描述 |
---|---|
fork() | 创建进程 |
exit() | 结束当前进程 |
wait() | 等待子进程结束 |
kill(pid) | 结束 pid 所指进程 |
getpid() | 获得当前进程 pid |
sleep(n) | 睡眠 n 秒 |
exec(filename, *argv) | 加载并执行一个文件 |
sbrk(n) | 为进程内存空间增加 n 字节 |
open(filename, flags) | 打开文件,flags 指定读/写模式 |
read(fd, buf, n) | 从文件中读 n 个字节到 buf |
write(fd, buf, n) | 从 buf 中写 n 个字节到文件 |
close(fd) | 关闭打开的 fd |
dup(fd) | 复制 fd |
pipe( p) | 创建管道, 并把读和写的 fd 返回到p |
chdir(dirname) | 改变当前目录 |
mkdir(dirname) | 创建新的目录 |
mknod(name, major, minor) | 创建设备文件 |
fstat(fd) | 返回文件信息 |
link(f1, f2) | 给 f1 创建一个新名字(f2) |
unlink(filename) | 删除文件 |
进程
系统调用 | 描述 |
---|---|
fork() | 创建进程 |
exit() | 结束当前进程 |
wait() | 等待子进程结束 |
kill(pid) | 结束 pid 所指进程 |
getpid() | 获得当前进程 pid |
exec(filename, *argv) | 加载并执行一个文件 |
sbrk(n) | 为进程内存空间增加 n 字节 |
I/O
系统调用 | 描述 |
---|---|
open(filename, flags) | 打开文件,flags 指定读/写模式 |
read(fd, buf, n) | 从文件中读 n 个字节到 buf |
write(fd, buf, n) | 从 buf 中写 n 个字节到文件 |
close(fd) | 关闭打开的 fd |
dup(fd) | 复制 fd |
代码示例:
1 | char buf[512]; |
不妨再来看看CSAPP的两张图
open两次:
fork:
管道
系统调用 | 描述 |
---|---|
pipe( p) | 创建管道, 并把读和写的 fd 返回到p,其中p是 int p[2] |
- p[0]: 读端(read end)的文件描述符
- p[1]: 写端(write end)的文件描述符
样例: grep fork sh.c | wc -l
命令将第一个命令(grep)的输出作为第二个命令(wc)的输入,|
就是管道符号。
下面的代码是 |
的实现示例,大体思路是把 |
左边的标准输出重定向到pipe的写端,把 |
右边的标准输入重定向到pipe的读端。
注意要关闭管道的所有写入端来让 read
返回,因为当 pipe 中没有数据时,read
会阻塞等待新数据写入,或是写入端都关闭,如果有新数据写入就读取,如果所有写入端都关闭就返回 0(对应EOF).
1 | // 假设我们的命令是 grep fork sh.c | wc -l |
文件系统
系统调用 | 描述 |
---|---|
chdir(dirname) | 改变当前目录 |
mkdir(dirname) | 创建新的目录 |
mknod(name, major, minor) | 创建设备文件 |
fstat(fd) | 返回文件信息 |
link(f1, f2) | 给 f1 创建一个新名字(f2) |
unlink(filename) | 删除文件 |
我们通常认为文件名就是文件本身,但实际上名称是一个硬链接(hard link)。一个文件可以有多个硬链接——例如,一个目录至少有两个硬链接:目录名和 .
(在目录内时)。它还有来自每个子目录的一个硬链接(每个子目录中的 ..
文件)。
那文件是什么呢?一个文件和一个 inode 一一对应,inode存放着这个文件的相关信息
xv6系统的inode结构包括下面这些内容:
1 | struct dinode { |
可以通过 fstat
获取文件描述符指向的文件的信息。dinode是磁盘上存储的详细信息,stat是暴露给用户的文件信息接口
1 | struct stat { |
仅当我们把所有指向某个inode的链接都删除,这个inode才会被删除。
在下面的示例中,我们用 ln
创建了两个连接 file2 和 file3,它们都和 file1 指向的 inode 相同。可以看到,如果用 echo
修改 file2,那么 file1 也会被修改,因为我们修改的实际上是 inode,而它们指向同一个inode。ls -l
列出目录中的文件和目录的详细信息,第二个值是inode的link数。我们可以把链接视作文件的“别名”。
1 | $ echo "What's in a name? That which we call a rose, by any other word would smell as sweet." > file1.txt |
你可能会好奇目录的链接数怎么计算,是这样的:
- 每个目录默认有2个链接,一个是目录自身的”.”,另一个是父目录中指向该目录的链接
- 目录中每包含一个子目录,链接数就会+1,因为每个子目录都会创建”..”链接指向父目录
在下面的例子中,rootdir 的链接数是 4,因为父目录有一个指向它的链接”rootdir”,它自己有一个指向自己的链接”.”,它的两个子目录dir1和dir2分别有指向它的链接”..”
1 | ~/open-course/rootdir$ ls |
文件路径格式:以 “/” 开头的是从根目录出发的路径,否则是从当前文件夹出发的路径
1 | ~/open-course$ ls |
unix shell的许多命令都是用户级别的,而非内置的。shell通过fork子进程并调用exec来执行它们。但cd是内置的,因为cd改变了shell自身的工作目录。
1 | // Read and run input commands. |