接上文 MIT XV6 - 1.1 Lab: Xv6 and Unix utilities - user/_sleep 是什么?做什么?
pingpong
不务正业了那么久(然而并没有,虽然还在探索sleep,但是教材我已经看完了前三章了),让我们赶紧继续下去
在进行本实验之前请务必阅读完教材 Chapter 1,尤其是1.3对于PIPE的介绍,实验具体要求如下:
Write a user-level program that uses xv6 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 “pid: received ping”, where pid 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 “pid: received pong”, and exit. Your solution should be in the file user/pingpong.c.
Some hints:
- Add the program to UPROGS in Makefile.
- Use pipe to create a pipe.
- Use fork to create a child.
- Use read to read from a pipe, and write to write to a pipe.
- Use getpid to find the process ID of the calling process.
- 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:
make qemu ... init: start sh $ pingpong 4: received ping 3: received pong $
整体还是比较简单的,主要你得理解fork和pipe的用法,以及一些要点,比如fork的返回值如果是子进程,那么会返回0;read会一直等到有足够的输入或者文件描述符被关闭啊。这些都在课本中有描述。
以下是实验源码(这注释,不用想,一定是AI写的…) GitHub已经同步
/*
* pingpong.c - A simple program demonstrating inter-process communication using pipes
*
* This program creates a parent-child process pair that communicate through a pipe.
* The parent sends a "ping" message to the child, and the child responds with a "pong".
*
* Communication Flow:
* 1. Parent creates a pipe
* 2. Parent forks a child process
* 3. Both processes have access to the pipe's read and write ends
* 4. Parent writes "p" to pipe and waits for response
* 5. Child reads "p" from pipe, prints "received ping", and writes "p" back
* 6. Parent reads "p" from pipe and prints "received pong"
*
* Timing Diagram:
*
* Parent Process Child Process
* | |
* |--pipe creation------>|
* | |
* |--fork()------------->|
* | |
* |--write("p")--------->|
* | |
* |<--read("p")----------|
* | |
* |<--write("p")---------|
* | |
* |--read("p")---------->|
* | |
* |--wait()------------->|
* | |
* |<--exit()-------------|
* | |
*/
#include "kernel/types.h" // Include kernel type definitions
#include "user/user.h" // Include user-level system call definitions
int main(int argc, char *argv[]) {
int p[2]; // Array to store pipe file descriptors
pipe(p); // Create a pipe, p[0] for reading, p[1] for writing
char buf[1]; // Buffer to store single character messages
if (fork() == 0) { // Child process
read(p[0], buf, 1); // Read "p" from parent
printf("%d: received ping\n", getpid()); // Print child's PID and message
write(p[1], "p", 1); // Send "p" back to parent
close(p[0]); // Close read end
close(p[1]); // Close write end
exit(0); // Exit child process
} else { // Parent process
write(p[1], "p", 1); // Send "p" to child
read(p[0], buf, 1); // Wait for child's response
printf("%d: received pong\n", getpid()); // Print parent's PID and message
wait(0); // Wait for child to exit
close(p[0]); // Close read end
close(p[1]); // Close write end
exit(0); // Exit parent process
}
return 0;
}
实验结果
make qemu
qemu-system-riscv64 -machine virt -bios none -kernel kernel/kernel -m 128M -smp 3 -nographic -global virtio-mmio.force-legacy=false -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 1 starting
hart 2 starting
init: starting sh
$ pingpong
4: received ping
3: received pong
$ QEMU: Terminated
ut结果
./grade-lab-util pingpong
make: `kernel/kernel' is up to date.
== Test pingpong == pingpong: OK (1.1s)
我觉得得找时间看看他ut都做了什么。