Sleep
easy
-
实现 Unix 程序
sleep
for xv6: 暂停指定的 ticks(ticks 的定义由xv6内核提供) 解决方案应该在user/sleep.c
- 提示:
- https://pdos.csail.mit.edu/6.S081/2020/xv6/book-riscv-rev1.pdf 的 Chapter 1
- 参考
user
目录下的其他命令 - 如果用户忘记传参数,应该返回错误信息
- 命令行参数应该以 string 类型传递,可以在代码层使用
user/lib.c
下的atoi
函数将字符串转换成一个 integer - 使用系统调用
sleep
- 查看
kernel/sysproc.c
中实现的sleep
系统调用,user/user.h
中定义了sleep
用户调用的函数名,user/usys.S
中的汇编代码实现了sleep
调用从用户态跳转到内核态 - 确保
main
调用exit()
结束代码 - 加入实现的
sleep
程序到 Makefile 的UPROGS
中。这样在重新 make qemu 时就能运行sleep
- 学习 C 语言开发
实验过程
- 运行:
-
make qemu sleep 10
- 进行评分
-
./grade-lab-util sleep
实验笔记
- {{embed ((68c3424b-2a2a-4e9f-b4ea-ab13675a5098))}}
- 核心代码:
#include "kernel/types.h" #include "kernel/stat.h" #include "user/user.h" int main(int argc, char **argv) { if (argc < 2) { printf("usage: sleep <ticks>\n"); exit(1); } sleep(atoi(argv[1])); exit(0); }
pingpong
easy
-
编写一个程序,程序使用 UNIX 的系统调用将一个字节“打乒乓球”似的在两个管道进程中传递。父进程发送一个字节到子进程,子进程应该打印
<pid>:received ping
,<pid>
是这个进程的PID,并且子进程写回这个字节给父进程,然后退出。父进程读取到这个子进程发送回的字节,打印<pid>: received pong
,然后退出。解决方案应该在user/pingpong.c
-
- 提示:
- 使用
pipe
创建一个管道 - 使用
fork
创建一个子进程 - 使用
read
从管道中读取,使用write
写入管道 - 添加到
UPROGS
到 Makefile - 用户程序的库是有限的
- 使用
- 核心代码:
#include "kernel/types.h" #include "kernel/stat.h" #include "user/user.h" int main(int argc, char **argv) { int pipe_p2c[2], pipe_c2p[2]; // 创建管道,在数组中写入管道读端和写端的文件描述符,[0]是读取端,[1]是写入端 pipe(pipe_p2c); pipe(pipe_c2p); char ball = '.'; if (fork() != 0) { write(pipe_p2c[1], &ball, 1); close(pipe_p2c[1]); char buf; read(pipe_c2p[0], &buf, 1); printf("%d: received pong\n", getpid()); wait(0); } else { char buf; read(pipe_p2c[0], &buf, 1); printf("%d: received ping\n", getpid()); write(pipe_c2p[1], &buf, 1); close(pipe_c2p[1]); } close(pipe_c2p[0]); close(pipe_p2c[0]); exit(0); }
Primes
hard
-
编写一个并发版本的质数筛。
{:height 175, :width 698}
- 核心代码:
#include "kernel/types.h" #include "kernel/stat.h" #include "user/user.h" #define END_MARKER -1 #define MAX_NUMBER 35 void sieve_process(int read_fd) { int prime; int bytes_read = read(read_fd, &prime, sizeof(prime)); if (bytes_read == 0 || prime == END_MARKER) { close(read_fd); exit(0); } printf("prime %d\n", prime); int next_pipe[2]; pipe(next_pipe); if (fork() == 0) { close(read_fd); close(next_pipe[1]); sieve_process(next_pipe[0]); } else { close(next_pipe[0]); int number; while (read(read_fd, &number, sizeof(number)) > 0) { if (number == END_MARKER) { write(next_pipe[1], &number, sizeof(number)); break; } if (number % prime != 0) { write(next_pipe[1], &number, sizeof(number)); } } close(read_fd); close(next_pipe[1]); wait(0); exit(0); } } int main(int argc, char **argv) { int numbers_pipe[2]; pipe(numbers_pipe); if (fork() == 0) { close(numbers_pipe[1]); sieve_process(numbers_pipe[0]); } else { close(numbers_pipe[0]); for (int i = 2; i <= MAX_NUMBER; i++) { write(numbers_pipe[1], &i, sizeof(i)); } int end_marker = END_MARKER; write(numbers_pipe[1], &end_marker, sizeof(end_marker)); close(numbers_pipe[1]); wait(0); } exit(0); }