XV6是一个简化的类似Unix的操作系统,而Unix是一个老的操作系统,但是同时也是很多现代操作系统的基础,例如Linux,OSX。所以Unix使用的非常广泛。而作为我们教学用的操作系统,XV6就要简单的多。它是受Unix启发创造的,有着相同的文件结构,但是却要比任何真实的Unix操作系统都要简单的多。因为它足够简单,所以你们极有可能在几周内很直观的读完所有的代码,同时也把相应的书也看完,这样你们就能理解XV6内部发生的一切事情了。
XV6运行在一个RISC-V微处理器上,而RISC-V是MIT6.004课程讲解的处理器,所以你们很多人可能已经知道了RISC-V指令集。理论上,你可以在一个RISC-V计算机上运行XV6,已经有人这么做了。但是我们会在一个QEMU模拟器上运行XV6。
我这里会写下来,我们的操作系统是XV6,它运行在RISC-V微处理器上,当然不只是RISC-V微处理器,我们假设有一定数量的其他硬件存在,例如内存,磁盘和一个console接口,这样我们才能跟操作系统进行交互。但是实际上,XV6运行在QEMU模拟器之上。这样你们都能在没有特定硬件的前提下,运行XV6。
接下来是一些例子
read, write, exit系统调用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| #include "kernel/types.h" #include "user/user.h"
int main () { char buf[64]; while (1) { int n = read(0, buf, sizeof(buf)); if (n <= 0) break; write(1, buf, n); } exit(0); }
|
open系统调用
1 2 3 4 5 6 7 8 9 10
| #include "kernel/types.h" #include "user/user.h" #include "kernel/fcntl.h"
int main () { int fd = open("output.txt", O_WRONLY | O_CREATE); write(fd, "Hello\n", 4); return 0; }
|
fork系统调用
fork创建了一个新的进程。当我们在Shell中运行东西的时候,Shell实际上会创建一个新的进程来运行你输入的每一个指令。所以,当我输入ls时,我们需要Shell通过fork创建一个进程来运行ls,这里需要某种方式来让这个新的进程来运行ls程序中的指令,加载名为ls的文件中的指令(也就是后面的exec系统调用)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| #include "kernel/types.h" #include "user/user.h"
int main () { int pid; pid = fork(); printf("fork() returned %d\n", pid); if (pid == 0) { printf("child\n"); } else { printf("parent\n"); }
exit(0); }
|
exec, wait系统调用
1 2 3 4 5 6 7 8 9 10 11
| #include "kernel/types.h" #include "user/user.h"
int main () { char *argv[] = {"echo", "this", "is", "echo", 0}; exec("echo", argv); printf("exec failed!\n");
exit(0); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| #include "kernel/types.h" #include "user/user.h"
int main () { int pid, status; pid = fork(); if (pid == 0) { char *argv[] = {"echo", "THIS", "IS", "ECHO", 0}; exec("echo", argv); printf("exec failed!\n"); exit(1); } else { printf("parent waiting!\n"); wait(&status); printf("the child exited with status %d\n", status); }
exit(0); }
|
I/O Redirect
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| #include "kernel/types.h" #include "user/user.h" #include "kernel/fcntl.h"
int main () { int pid; pid = fork(); if (pid == 0) { close(1); open("output.txt", O_WRONLY|O_CREATE); char *argv[] = {"echo", "this", "is", "redirected", 0}; exec("echo", argv); exit(1); } else { wait((int*) 0); }
exit(0); }
|
pipe
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| #include "kernel/types.h" #include "user/user.h"
int main () { int fds[2]; char buf[100]; int n; pipe(fds); write(fds[1], "this is pipe1\n", 14); n = read(fds[0], buf, sizeof(buf)); write(1, buf, n);
exit(0); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| #include "kernel/types.h" #include "user/user.h"
int main () { int n, pid; int fds[2]; char buf[100]; pipe(fds); pid = fork(); if (pid == 0) { write(fds[1], "this is pipe2\n", 14); } else { n = read(fds[0], buf, sizeof(buf)); write(1, buf, n); }
exit(0); }
|