本文记录了 Labs:Xv6 and Unix utilities 的实验过程
实验链接
启动 xv6 拉取 xv6 的源码(如果已经 clone
了源码则跳过这一步)
1 git clone git://g.csail.mit.edu/xv6-labs-2020
进入该 Lab 的分支
1 2 cd xv6-labs-2020git checkout util
build 以及 运行 xv6
xv6 没有 ps
(列出系统中当前运行的进程) 命令;但可以使用 Ctrl-p
,内核将打印进程的信息。
退出 qemu
Grading 和 hand-in 程序
运行 make grade
(该命令会测试该 Lab 下的所有程序) 将使用 grading
程序测试你的代码。如果只是想测试一个程序,可以使用如
注:需要安装 python3,sudo apt-get install python-is-python3
。
使用 make handin
来提交你的 Lab。
1、Sleep (easy) 思路
读取命令行中 sleep
程序后面的参数,使用已提供的 atoi
函数将参数转化为整数,然后执行 sleep
系统调用。
实验步骤
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 #include "kernel/tpes.h" #include "kernel/stat.h" #include "user/user.h" int main(int argc, char *argv[]) { int n; if (argc != 2 ){ fprintf (2 , "please give sleep process a argument.\n" ); exit (1 ); } n = atoi(argv[1 ]); sleep(n); exit (0 ); }
然后在 xv6-labs-2020
目录的 Makefile
中找到 UPROGS
,添加 $U/_sleep\
。回到 xv6-labs-2020
目录,输入./grade-lab-util sleep
查看能否通过测试
2、pingpong(easy) 思路
一个进程可以通过系统调用 fork
来创建一个新的进程。fork
创建的新进程被称为子进程 ,子进程的内存内容同创建它的进程(父进程)一样。fork
函数在父进程、子进程中都返回(一次调用两次返回)。对于父进程它返回子进程的 pid,对于子进程它返回 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 #include "kernel/tpes.h" #include "kernel/stat.h" #include "user/user.h" int main(void ) { char buf[512 ]; int fd1[2 ], fd2[2 ]; pipe(fd1); pipe(fd2); int pid = fork(); if (pid < 0 ) { fprintf (2 , "fork error.\n" ); exit (1 ); } if (pid == 0 ) { read (fd1[1 ], buf, 1 ); fprintf (1 , "%d: received ping\n" , getpid()); write (fd2[0 ], buf, 1 ); exit (0 ); } else { write (fd1[0 ], buf, 1 ); read (fd2[1 ], buf, 1 ); wait(0 ); fprintf (1 , "%d: received pong\n" , getpid()); } exit (0 ); }
思路
首先在父进程中,我们向管道写入数 2~35,然后由子进程执行埃氏筛法。
实验过程 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 #include "kernel/tpes.h" #include "kernel/stat.h" #include "user/user.h" void solution (int fd[]) { int prime; if (read (fd[0 ], &prime, sizeof (prime)) == 0 ){ exit (0 ); } printf ("prime %d\n" , prime); int child_fd[2 ]; pipe(child_fd); if (fork() == 0 ){ close (child_fd[1 ]); solution(child_fd); }else { close (child_fd[0 ]); int num; while (read (fd[0 ], &num, sizeof (num)) != 0 ){ if (num % prime != 0 ){ write (child_fd[1 ], &num, sizeof (num)); } } close (child_fd[1 ]); } wait(0 ); exit (0 ); } int main(void ) { int fd[2 ]; pipe(fd); int x = 2 ; if (fork() == 0 ){ close (fd[1 ]); solution(fd); }else { close (fd[0 ]); for (; x <= 35 ; x++){ write (fd[1 ], &x, sizeof (x)); } close (fd[1 ]); } wait(0 ); exit (0 ); }
思路
理解 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 #include "kernel/tpes.h" #include "kernel/stat.h" #include "user/user.h" #include "kernel/fs.h" void find (char *path, char *name){ char buf[512 ], *p; int fd; struct dirent de ; struct stat st ; if ((fd = open (path, 0 )) < 0 ){ return ; } if (fstat(fd, &st) < 0 ){ close (fd); return ; } switch (st.type){ case T_FILE: break ; case T_DIR: strcpy (buf, path); p = buf + strlen (buf); *p++ = '/' ; while (read (fd, &de, sizeof (de)) == sizeof (de)){ if (de.inum == 0 ) continue ; if (strcmp (de.name, "." ) == 0 || strcmp (de.name, ".." ) == 0 ) continue ; memmove(p, de.name, DIRSIZ); p[DIRSIZ] = 0 ; if (strcmp (name, de.name) == 0 ) { printf ("%s\n" , buf); } find (buf, name); } break ; } close (fd); } int main(int argc, char *argv[]) { if (argc < 3 ){ exit (0 ); } find (argv[1 ], argv[2 ]); exit (0 ); }
注
|
:管道命令,是将左侧命令的标准输出转换为标准输入,提供给右侧命令作为参数。例如
1 echo hello too | xargs echo bye
将左侧的标准输入,转为命令行参数 hello too
,传给第二个 echo
。xargs
命令的作用,是将标准输入转为命令行参数。
思路
由于 |
左边的参数在标准输出中,因此我们需要按空格从标准输入中读取各个参数保存起来。拼接到 |
右边的参数中。然后调用 exec
执行 xargs
后面的命令。
实验过程 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 #include "kernel/types.h" #include "kernel/param.h" #include "user/user.h" #define MAX 512 int main(int argc, char *argv[]) { char *args[MAXARG]; char buf[MAX]; int args_idx = 0 ; for (int i = 1 ; i < argc; ++i){ args[args_idx++] = argv[i]; } int n; while ((n = read (0 , buf, MAX)) > 0 ){ if (fork() == 0 ){ char *para = (char *)malloc (sizeof (buf)); int idx = 0 ; for (int i = 0 ; i < n; i++){ if (buf[i] == ' ' || buf[i] == '\n' ){ para[idx] = 0 ; args[args_idx++] = para; idx = 0 ; para = (char *)malloc (sizeof (buf)); }else { para[idx++] = buf[i]; } } args[args_idx] = 0 ; exec(args[0 ], args); }else { wait(0 ); } } exit (0 ); }
测试