本实验将让你熟悉xv6及其系统调用。
你可以在Athena机器上或你自己的电脑上完成这些实验。如果你使用自己的电脑,请查看实验工具页面获取设置提示。
如果你使用Athena,你必须使用x86机器;也就是说,uname -a应该显示i386 GNU/Linux或i686 GNU/Linux或x86_64 GNU/Linux。你可以使用ssh -X athena.dialup.mit.edu登录公共Athena主机。我们已经在Athena上为你设置好了相应的编译器和模拟器。要使用它们,运行add -f 6.828。每次登录时你必须运行此命令(或将其添加到你的~/.environment文件中)。如果在编译或运行qemu时遇到不明错误,请检查你是否添加了课程locker。
获取实验的xv6源代码并切换到util分支:
$ git clone git://g.csail.mit.edu/xv6-labs-2020 Cloning into 'xv6-labs-2020'... ... $ cd xv6-labs-2020 $ git checkout util Branch 'util' set up to track remote branch 'util' from 'origin'. Switched to a new branch 'util'
xv6-labs-2020仓库与书中的xv6-riscv略有不同;它主要增加了一些文件。如果你好奇,可以查看git日志:
$ git log
本实验及后续实验所需的文件通过Git版本控制系统分发。上面你切换到了一个包含为本实验定制的xv6版本的分支(git checkout util)。要了解更多关于Git的知识,请查看Git用户手册,或者你可能会发现这个面向计算机科学家的Git概述很有用。Git允许你跟踪对代码所做的更改。例如,如果你完成了其中一个练习,想要保存进度,你可以通过运行以下命令来提交你的更改:
$ git commit -am 'my solution for util lab exercise 1' Created commit 60d2135: my solution for util lab exercise 1 1 files changed, 1 insertions(+), 0 deletions(-) $
你可以使用git diff命令来跟踪你的更改。运行git diff将显示自上次提交以来对代码的更改,而git diff origin/util将显示相对于初始xv6-labs-2020代码的更改。这里,origin/xv6-labs-2020是你为课程下载的初始代码所在的git分支名称。
编译并运行xv6:
$ make qemu riscv64-unknown-elf-gcc -c -o kernel/entry.o kernel/entry.S riscv64-unknown-elf-gcc -Wall -Werror -O -fno-omit-frame-pointer -ggdb -DSOL_UTIL -MD -mcmodel=medany -ffreestanding -fno-common -nostdlib -mno-relax -I. -fno-stack-protector -fno-pie -no-pie -c -o kernel/start.o kernel/start.c ... riscv64-unknown-elf-ld -z max-page-size=4096 -N -e main -Ttext 0 -o user/_zombie user/zombie.o user/ulib.o user/usys.o user/printf.o user/umalloc.o riscv64-unknown-elf-objdump -S user/_zombie > user/zombie.asm riscv64-unknown-elf-objdump -t user/_zombie | sed '1,/SYMBOL TABLE/d; s/ .* / /; /^$/d' > user/zombie.sym mkfs/mkfs fs.img README user/xargstest.sh user/_cat user/_echo user/_forktest user/_grep user/_init user/_kill user/_ln user/_ls user/_mkdir user/_rm user/_sh user/_stressfs user/_usertests user/_grind user/_wc user/_zombie nmeta 46 (boot, super, log blocks 30 inode blocks 13, bitmap blocks 1) blocks 954 total 1000 balloc: first 591 blocks have been allocated balloc: write bitmap block at sector 45 qemu-system-riscv64 -machine virt -bios none -kernel kernel/kernel -m 128M -smp 3 -nographic -drive file=fs.img,if=none,format=raw,id=x0 -device virtio-blk-device,drive=x0,bus=virtio-mmio-bus.0 xv6 kernel is booting hart 2 starting hart 1 starting init: starting sh $
如果在提示符处输入ls,你应该看到类似以下的输出:
$ ls . 1 1 1024 .. 1 1 1024 README 2 2 2059 xargstest.sh 2 3 93 cat 2 4 24256 echo 2 5 23080 forktest 2 6 13272 grep 2 7 27560 init 2 8 23816 kill 2 9 23024 ln 2 10 22880 ls 2 11 26448 mkdir 2 12 23176 rm 2 13 23160 sh 2 14 41976 stressfs 2 15 24016 usertests 2 16 148456 grind 2 17 38144 wc 2 18 25344 zombie 2 19 22408 console 3 20 0这些是mkfs包含在初始文件系统中的文件;大多数是你可以运行的程序。你刚刚运行了其中一个:ls。
xv6没有ps命令,但是,如果你按Ctrl-p,内核将打印每个进程的信息。如果你现在尝试,你会看到两行:一行是init的,一行是sh的。
要退出qemu,按:Ctrl-a x.
你可以运行make grade来用评分程序测试你的解决方案。助教将使用相同的评分程序来为你的实验提交评分。另外,我们还会有实验的检查会议(参见评分政策)。
实验代码附带GNU Make规则以简化提交流程。在提交实验的最终更改之后,输入make handin来提交你的实验。有关如何提交的详细说明,请参见下方。
为xv6实现UNIX程序sleep;你的sleep应该暂停用户指定的tick数。tick是xv6内核定义的时间概念,即定时器芯片两次中断之间的时间。你的解决方案应该在文件user/sleep.c中。
一些提示:
从xv6 shell运行该程序:
如果你的程序在如上所示运行时暂停,则你的解决方案是正确的。运行make grade来确认你确实通过了sleep测试。
请注意,make grade会运行所有测试,包括下面作业的测试。如果你只想运行一个作业的评分测试,请输入:
编写一个程序,使用UNIX系统调用通过一对管道在两个进程之间"乒乓"一个字节,每个方向一个管道。父进程应该向子进程发送一个字节;子进程应该打印"<pid>: received ping",其中<pid>是其进程ID,将字节通过管道写给父进程,然后退出;父进程应该从子进程读取字节,打印"<pid>: received pong",然后退出。你的解决方案应该在文件user/pingpong.c中。
一些提示:
从xv6 shell运行该程序,它应该产生以下输出:
如果你的程序在两个进程之间交换了一个字节并产生了如上所示的输出,则你的解决方案是正确的。
使用管道编写素数筛的并发版本。这个想法来自Doug McIlroy,Unix管道的发明者。这个页面中间的图片及其周围的文字解释了如何实现。你的解决方案应该在文件user/primes.c中。
你的目标是使用pipe和fork来设置管道。第一个进程将数字2到35送入管道。对于每个素数,你将安排创建一个进程,该进程通过管道从其左邻居读取数据,并通过另一个管道向其右邻居写入数据。由于xv6的文件描述符和进程数量有限,第一个进程可以在35处停止。
一些提示:
如果它实现了基于管道的筛法并产生以下输出,则你的解决方案是正确的:
编写UNIX find程序的简单版本:查找目录树中所有具有特定名称的文件。你的解决方案应该在文件user/find.c中。
一些提示:
如果产生以下输出(当文件系统包含文件b和a/b时),则你的解决方案是正确的:
编写UNIX xargs程序的简单版本:从标准输入读取行,并为每一行运行一个命令,将该行作为命令的参数。你的解决方案应该在文件user/xargs.c中。
请注意,UNIX上的xargs做了一个优化,它会一次向命令传递多个参数。我们不希望你做这个优化。要使UNIX上的xargs按照本实验的要求运行,请使用-n选项设置为1。例如 一些提示:
xargs、find和grep组合使用效果很好:
要测试你的xargs解决方案,请运行shell脚本xargstest.sh。如果产生以下输出,则你的解决方案是正确的:
>
实验到此完成。确保你通过了所有make grade测试。如果本实验有问题,别忘了在answers-lab-name.txt中写下你的答案。提交你的更改(包括添加answers-lab-name.txt),然后在实验目录中输入make handin来提交你的实验。
创建一个新文件time.txt,在其中放入一个整数,表示你花在本实验上的小时数。别忘了git add和git commit该文件。
在提交实验的最终更改之后,输入make handin来提交你的实验。
评分与提交流程
sleep
$ make qemu
...
init: starting sh
$ sleep 10
(nothing happens for a little while)
$
$ ./grade-lab-util sleep
这将运行匹配"sleep"的评分测试。或者,你可以输入:
$ make GRADEFLAGS=sleep grade
效果相同。
pingpong
$ make qemu
...
init: starting sh
$ pingpong
4: received ping
3: received pong
$
primes /
$ make qemu
...
init: starting sh
$ primes
prime 2
prime 3
prime 5
prime 7
prime 11
prime 13
prime 17
prime 19
prime 23
prime 29
prime 31
$
find
$ make qemu
...
init: starting sh
$ echo > b
$ mkdir a
$ echo > a/b
$ find . b
./b
./a/b
$
xargs
$ echo hello too | xargs echo bye
bye hello too
$
注意这里的命令是"echo bye",额外的参数是"hello too",组成命令"echo bye hello too",输出"bye hello too"。
$ echo "1\n2" | xargs -n 1 echo line
line 1
line 2
$
$ find . b | xargs grep hello
将在"."以下目录中每个名为b的文件上运行"grep hello"。
$ make qemu
...
init: starting sh
$ sh < xargstest.sh
$ $ $ $ $ $ hello
hello
hello
$ $
你可能需要回去修复find程序中的bug。输出中有很多$,因为xv6 shell没有意识到它在处理来自文件的命令而不是来自控制台的命令,所以为文件中的每个命令打印一个$。
提交实验
花费时间
提交
你将使用提交网站提交你的作业。在提交任何作业或实验之前,你需要从提交网站申请一次API密钥。
$ git commit -am "ready to submit my lab"
[util c2e3c8b] ready to submit my lab
2 files changed, 18 insertions(+), 2 deletions(-)
$ make handin
tar: Removing leading `/' from member names
Get an API key for yourself by visiting https://6828.scripts.mit.edu/2020/handin.py/
Please enter your API key: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 79258 100 239 100 79019 853 275k --:--:-- --:--:-- --:--:-- 276k
$
make handin会将你的API密钥存储在myapi.key中。如果你需要更改API密钥,只需删除此文件,然后让make handin重新生成(myapi.key不能包含换行符)。
如果你运行make handin时有未提交的更改或未跟踪的文件,你将看到类似以下的输出:
M hello.c ?? bar.c ?? foo.pyc Untracked files will not be handed in. Continue? [y/N]检查上述行,确保你的实验解决方案所需的所有文件都被跟踪,即不在以??开头的行中列出。你可以使用git add filename让git跟踪你创建的新文件。
如果make handin不能正常工作,请尝试修复curl或Git命令的问题。或者你可以运行make tarball。这将为你制作一个tar文件,然后你可以通过我们的web界面上传。
编写一个uptime程序,使用uptime系统调用以tick为单位打印运行时间。
在find的名称匹配中支持正则表达式。grep.c有一些基本的正则表达式支持。
xv6 shell(user/sh.c)只是另一个用户程序,你可以改进它。它是一个最小的shell,缺少许多真实shell中的功能。例如,修改shell使其在处理来自文件的shell命令时不打印$,修改shell以支持wait,修改shell以支持用";"分隔的命令列表,修改shell通过实现"("和")"来支持子shell,修改shell以支持tab补全,修改shell以保留已执行的shell命令的历史记录,或者任何你希望shell实现的功能。(如果你非常有野心,你可能需要修改内核以支持你需要的内核特性;xv6不支持太多特性。)