#include"kernel/types.h" #include"kernel/stat.h" #include"user/user.h" intmain(int argc,char *argv[]){ if(argc <= 1){ exit(1); } int time = atoi(argv[1]); sleep(time); exit(0); }
这个实验相当简单,就是让你使用一下系统调用 sleep()。
4、测试
1 2 3 4 5
******:~/xv6-labs-2023# ./grade-lab-util sleep make: 'kernel/kernel' is up to date. == Test sleep, no arguments == sleep, no arguments: OK (1.1s) == Test sleep, returns == sleep, returns: OK (0.8s) == Test sleep, makes syscall == sleep, makes syscall: OK (1.0s)
测试都通过了。
现在就可以顺利地做试验了,把剩下的任务都完成一下。
三、完成所有实验
1、pingpong(easy)
Question requirements
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.
Some hints
Use pipe to create a pipe.
Use fork to create a child.
Use read to read from the pipe, and write to write to the pipe.
Use getpid to find the process ID of the calling process.
Add the program to UPROGS in Makefile.
User programs on xv6 have a limited set of library functions available to them. You can see - the list in user/user.h;
the source (other than for system calls) is in user/ulib.c, user/printf.c, and
user/umalloc.c.
Run the program from the xv6 shell and it should produce the following output
1 2 3 4 5 6 7
$ make qemu ... init: starting sh $ pingpong 4: received ping 3: received pong $
Write a concurrent version of prime sieve using pipes. This idea is due to Doug McIlroy, inventor of Unix pipes. The picture halfway down this page and the surrounding text explain how to do it. Your solution should be in the file user/primes.c.
Some hints
Be careful to close file descriptors that a process doesn’t need, because otherwise your program will run xv6 out of resources before the first process reaches 35.
Once the first process reaches 35, it should wait until the entire pipeline terminates, including all children, grandchildren, &c. Thus the main primes process should only exit after all the output has been printed, and after all the other primes processes have exited.
Hint: read returns zero when the write-side of a pipe is closed. It’s simplest to directly write 32-bit (4-byte) ints to the pipes, rather than using formatted ASCII I/O.
You should create the processes in the pipeline only as they are needed.
Add the program to UPROGS in Makefile.
Your solution is correct if it implements a pipe-based sieve and produces the following output:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
$ 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 $
}elseif(pid > 0){ close(p[0]); // 父进程将数据传给子进程 for(int i = 2; i <= 35; i++){ write(p[1], &i,sizeof(int)); } close(p[1]); int status; wait(&status); }else{ fprintf(1, "err for fork()\n"); exit(1); }
exit(0); }
Output
1 2 3 4 5 6 7 8 9 10 11 12 13
$ primes prime 2 prime 3 prime 5 prime 7 prime 11 prime 13 prime 17 prime 19 prime 23 prime 29 prime 31 $
Notes
这题目还是用递归比较好,递归的出口就是 read() 返回为 0;
将管道作为参数传递给另一个函数时,实际上传递的是指向管道的文件描述符数组的指针。
3、find (moderate)
Question requirements
Write a simple version of the UNIX find program: find all the files in a directory tree with a specific name. Your solution should be in the file user/find.c.
Some hints
Look at user/ls.c to see how to read directories.
Use recursion to allow find to descend into sub-directories.
Don’t recurse into “.” and “..”.
Changes to the file system persist across runs of qemu; to get a clean file system run make clean and then make qemu.
You’ll need to use C strings. Have a look at K&R (the C book), for example Section 5.5.
Note that == does not compare strings like in Python. Use strcmp() instead.
Add the program to UPROGS in Makefile.
Your solution is correct if produces the following output (when the file system contains the files b and a/b):
1 2 3 4 5 6 7 8 9 10
$ make qemu ... init: starting sh $ echo > b $ mkdir a $ echo > a/b $ find . b ./b ./a/b $
structstat { int dev; // File system's disk device uint ino; // Inode number short type; // Type of file short nlink; // Number of links to file uint64 size; // Size of file in bytes };
******:~/xv6-labs-2023# ./grade-lab-util find make: 'kernel/kernel' is up to date. == Test find, in current directory == find, in current directory: OK (1.8s) == Test find, recursive == find, recursive: OK (1.2s)
Notes
能调用 OS 提供的用户调用,就尽量避免直接调用系统调用。
4、xargs (moderate)
Question requirements
Write a simple version of the UNIX xargs program for xv6: its arguments describe a command to run, it reads lines from the standard input, and it runs the command for each line, appending the line to the command’s arguments. Your solution should be in the file user/xargs.c.
Some hints
Use fork and exec to invoke the command on each line of input. Use wait in the parent to wait for the child to complete the command.
To read individual lines of input, read a character at a time until a newline (‘\n’) appears.
kernel/param.h declares MAXARG, which may be useful if you need to declare an argv array.
Add the program to UPROGS in Makefile.
Changes to the file system persist across runs of qemu; to get a clean file system run make clean and then make qemu.
意思就是说,使用 fork、exec 来执行命令;每次读取一个字符,直到读完一行。
To test your solution for xargs, run the shell script xargstest.sh. Your solution is correct if it produces the following output
1 2 3 4 5 6 7 8 9
$ make qemu ... init: starting sh $ sh < xargstest.sh $ $ $ $ $ $ hello hello hello $ $
******:~/xv6-labs-2023# ./grade-lab-util xargs make: 'kernel/kernel' is up to date. == Test xargs == xargs: OK (2.1s)
Notes
exec()和 Linux 中的系统调用还是有一些差别,书中说的是:
This fragment replaces the calling program with an instance of the program /bin/echo running with the argument list echo hello. Most programs ignore the first element of the argument array, which is conventionally the name of the program.
== Test sleep, no arguments == $ make qemu-gdb sleep, no arguments: OK (3.3s) == Test sleep, returns == $ make qemu-gdb sleep, returns: OK (1.1s) == Test sleep, makes syscall == $ make qemu-gdb sleep, makes syscall: OK (1.0s) == Test pingpong == $ make qemu-gdb pingpong: OK (1.1s) == Test primes == $ make qemu-gdb primes: OK (1.0s) == Test find, in current directory == $ make qemu-gdb find, in current directory: OK (1.1s) == Test find, recursive == $ make qemu-gdb find, recursive: OK (1.4s) == Test xargs == $ make qemu-gdb xargs: OK (1.9s) == Test time == time: OK Score: 100/100