Lab 1 是让我们在 user 文件夹下编写五个用户程序
Sleep(easy) Implement the UNIX program sleep for xv6; your sleep should pause for a user-specified number of ticks. A tick is a notion of time defined by the xv6 kernel, namely the time between two interrupts from the timer chip. Your solution should be in the file user/sleep.c.  这里的目的即是停顿一段时间,时间即是 sleep 后的 ticks 参数 Run the program from the xv6 shell:
1 2 3 4 5 6 $ make qemu ... init: starting sh $ sleep 10 (nothing happens for a little while) $ 
 
这里只需要使用 sleep 系统调用即可,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 #include "kernel/types.h" #include "kernel/stat.h" #include "user/user.h" int main(int argc, char *argv[]) {     if (argc != 2) { // 检查参数数量         exit(1);      }     int ticks = atoi(argv[1]); // 命令行中的数字是字符串,将其转化成int型     if (ticks < 0) { // 判断时间参数         exit(1);     }     sleep(ticks); // sleep系统调用     exit(0); } 
 
在 makefile 中添加应用程序     $U/_sleep 对其进行单独测试
1 $ make GRADEFLAGS=sleep grade 
 
pingpong(easy) Write a program that uses UNIX system calls to ‘’ping-pong’’ a byte between two processes over a pair of pipes, one for each direction. The parent should send a byte to the child; the child should print “: received ping”, where  is its process ID, write the byte on the pipe to the parent, and exit; the parent should read the byte from the child, print “: received pong”, and exit. Your solution should be in the file user/pingpong.c.     即通过pipe管道实现父子进程的通信
 
这里需要用到几个系统调用,xv6-book第一章开头有提供系统调用的介绍
int pipe(int p[])  
int write(int fd, char *buf, int n) 
int read(int fd, char *buf, int n)
系统调用 
描述 
 
 
int fork() 
创建一个进程 返回子进程的PID 
 
int exit(int status) 
终止当前进程 并将状态报告给wait()函数 无返回 
 
int wait(int *status) 
等待一个子进程退出 将退出状态存入*status 返回子进程PID 
 
int kill(int pid) 
终止对应PID的进程返回0或返回-1表示错误 
 
int getpid() 
返回当前进程的PID 
 
int sleep(int n) 
暂停n个时钟节拍 
 
int exec(char *file, char *argv[]) 
加载一个文件并使用参数执行 它只有在出错时才返回 
 
char *sbrk(int n) 
按n字节增长进程的内存 返回新内存的开始 
 
int open(char *file, int flags) 
打开一个文件 flags表示read/write 返回一个fd(文件描述符 
 
int write(int fd, char *buf, int n) 
从buf写n个字节到文件描述符fd 返回n 
 
int read(int fd, char *buf, int n) 
将n个字节读入buf 返回读取的字节数 如果文件结束 返回0 
 
int close(int fd) 
释放打开的文件fd 
 
int dup(int fd) 
返回一个新的文件描述符 指向与fd相同的文件 
 
int pipe(int p[]) 
创建一个管道 把read/write文件描述符放在p[0]和p[1]中 
 
int chdir(char *dir) 
改变当前的工作目录 
 
int mkdir(char *dir) 
创建一个新目录 
 
int mknod(char *file, int, int) 
创建一个设备文件 
 
int fstat(int fd, struct stat *st) 
将打开文件fd的信息放入*st 
 
int stat(char *file, struct stat *st) 
将指定名称的文件信息放入*st 
 
int link(char *file1, char *file2) 
为文件file1创建另一个名称(file2) 
 
int unlink(char *file) 
删除一个文件 
 
 
 
其中特别注意当使用两个管道进行父子进程通信时,如果管道的写端没有关闭,那么管道中数据为空时对管道的读取将会阻塞.因此,为了避免读端一直阻塞,需要尽快关闭不需要的管道描述符,特别是写端。这样可以让read()系统调用在没有数据时返回0,而不是无限期地阻塞。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 #include "kernel/types.h" #include "user/user.h" #define RE 0 // pipe read port #define WR 1 // pipe write port int main(int argc, char *argv[]) {     char byte = 'A'; //the byte will be sent          int p_fd[2];     int c_fd[2];     pipe(p_fd);     pipe(c_fd);     int pid = fork();     int exit_status = 0;     if (pid < 0) {         fprintf(2, "fork() error!\n");         close(c_fd[RE]);         close(c_fd[WR]);         close(p_fd[RE]);         close(p_fd[WR]);                exit(1);     } else if (pid == 0) { // child process         close(c_fd[RE]);         close(p_fd[WR]);         if (read(p_fd[RE], &byte, sizeof(char)) != sizeof(char)) {             fprintf(2, "child read() error!\n");             exit_status = 1;         } else {             fprintf(1, "%d: received ping\n", getpid());         }         if (write(c_fd[WR], &byte, sizeof(char)) != sizeof(char)) {             fprintf(2, "child write() error!\n");             exit_status = 1;         }         close(c_fd[WR]);         close(p_fd[RE]);         exit(exit_status);     } else { //parent process         close(p_fd[RE]);         close(c_fd[WR]);                  if (write(p_fd[WR], &byte, sizeof(char)) != sizeof(char)) {             fprintf(2, "parent write() error!\n");             exit_status = 1;         }                  if (read(c_fd[RE], &byte, sizeof(char)) != sizeof(char)) {             fprintf(2, "parent read() error!\n");             exit_status = 1;         } else {             fprintf(1, "%d: received pong\n", getpid());         }                  close(c_fd[RE]);         close(p_fd[WR]);                 exit(exit_status);     } } 
 
在 makefile 中添加应用程序
 
对其进行单独测试
1 $ make GRADEFLAGS=pingpong grade 
 
Primes(Moderate/Hard) Write a concurrent version of prime sieve using pipes. This idea is due to Doug McIlroy, inventor of Unix pipes.Your solution should be in the file user/primes.c.  参考资料
1 2 3 4 5 6 p = get a number from left neighbor print p loop:     n = get a number from left neighbor     if (p does not divide n)         send n to right neighbor 
 
 本质上是一个递归,通过管道传输数字
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 #include "kernel/types.h" #include "user/user.h" #define RE 0 // pipe read port #define WR 1 // pipe write port int lpipe_fir(int lpipe[2], int *dst) { //接受左管道的第一个数字,如果没有返回-1     if (read(lpipe[RE], dst, sizeof(int)) == sizeof(int)) {         printf("prime %d\n", *dst);         return 0;     }     return -1; } void trans(int lpipe[2], int rpipe[2], int first) { //传递给右管道     int data;     while (read(lpipe[RE], &data, sizeof(int)) == sizeof(int)) {         if (data % first) {             write(rpipe[WR], &data, sizeof(int));         }     }     close(lpipe[RE]);     close(rpipe[WR]); } void primes(int lpipe[2]) {     close(lpipe[WR]);     int first;     if (lpipe_fir(lpipe, &first) == 0) {         int fd[2];         pipe(fd);         trans(lpipe, fd, first);         int pid = fork();                  if (pid == 0) {             primes(fd); //递归         } else {             close(fd[RE]);             wait(0);         }     }     exit(0); } int main(int argc, char *argv[]) {     int init_fd[2];     pipe(init_fd);     for (int i = 2; i <= 35; i++) {         write(init_fd[WR], &i, sizeof(int));     }     int pid = fork();     if (pid == 0) {         primes(init_fd);     } else {         close(init_fd[WR]);         close(init_fd[RE]);         wait(0);     }     exit(0); }  
 
在 makefile 中添加应用程序     $U/_primes 对其进行单独测试
1 $ make GRADEFLAGS=pingpong grade 
 
find (Moderate) 基本就是copy user/ls.c 的代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 #include "kernel/types.h" #include "kernel/stat.h" #include "user/user.h" #include "kernel/fs.h" void find(char *path, const char *target) {     char buf[512];     char *p;     int fd;     struct dirent de;     struct stat st;     if ((fd = open(path, 0)) < 0) {         fprintf(2, "ls: cannot open %s\n", path);         return;     }     if (fstat(fd, &st) < 0) {         fprintf(2, "ls: cannot stat %s\n", path);         close(fd);         return;     }     if (st.type != T_DIR) {         fprintf(2, "usage: find <DIRECTORY> <filename>\n");         return;     }     if (strlen(path) + 1 + DIRSIZ + 1 > sizeof buf) {         fprintf(2, "find: path too long\n");         return;     }     strcpy(buf, path);     p = buf + strlen(buf);     *p++ = '/'; //p指向最后一个'/'之后     while (read(fd, &de, sizeof de) == sizeof de) {         if (de.inum == 0) {             continue;         }         memmove(p, de.name, DIRSIZ); //添加路径名称         p[DIRSIZ] = 0;               //字符串结束标志         if (stat(buf, &st) < 0) {             fprintf(2, "find: cannot stat %s\n", buf);             continue;         }         //不要在“.”和“..”目录中递归         if (st.type == T_DIR && strcmp(p, ".") != 0 && strcmp(p, "..") != 0) {             find(buf, target);         } else if (strcmp(target, p) == 0) {             printf("%s\n", buf);         }     }     close(fd);  } int main(int argc, char *argv[]) {     if (argc != 3) {         exit(1);     }     find(argv[1], argv[2]);     exit(0); }