实现几个unix实用工具,熟悉xv6的开发环境以及系统调用
实验环境搭建:使用Ubuntu20.04
- Sleep (easy)
参考user/echo.c,添加头文件
#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
参考user/ulib.c,把命令行参数string类型转换为int,使用atoi
在Makefile里把sleep加入构建目标里
UPROGS=\
$U/_cat\
$U/_echo\
$U/_forktest\
$U/_grep\
$U/_init\
$U/_kill\
$U/_ln\
$U/_ls\
$U/_mkdir\
$U/_rm\
$U/_sh\
$U/_stressfs\
$U/_usertests\
$U/_grind\
$U/_wc\
$U/_zombie\
$U/_sleep\
代码:
#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
int main(int argc, char *argv[]) {
if (argc != 2) {
fprintf(2, "Please enter a number\n");
exit(1);
} else {
sleep(atoi(argv[1]));
exit(0);
}
}
测试
注意:评测脚本是python程序
第一行修改为:
!/usr/bin/ python
测试命令修改为:
python3 grade-lab-util sleep
捕获.PNG
- pingpong(easy)
管道是一个小的内核缓冲区,它以文件描述符对的形式提供给进程,一个用于写操作,一个用于读操作。按照惯例,进程从文件描述符0读入(标准输入),从文件描述符1输出(标准输出)。
方式一:创建2个管道,分别用于父子进程之间两个方向的数据传输
#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
int
main(int argc, char *argv[])
{
int p2c[2], c2p[2];
pipe(p2c);
pipe(c2p);
if (fork() != 0) {
write(p2c[1], "f", 1);
char buf;
read(c2p[0], &buf, 1);
printf("%d: received pong\n", getpid());
wait(0);
} else {
char buf;
read(p2c[0], &buf, 1);
printf("%d: received ping\n", getpid());
write(c2p[1], &buf, 1);
}
exit(0);
}
测试结果:
pingpong2.PNG
pingpong1.PNG
方式二:创建1个管道
父子进程复用管道
#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
int
main(int argc, char *argv[])
{
int p[2];
pipe(p);
if (fork() == 0) {
char buf;
read(p[0], &buf, 1);
close(p[0]);
printf("%d: received ping\n", getpid());
write(p[1], "c", 1);
close(p[1]);
exit(0);
} else {
char buf;
write(p[1], "f", 1);
close(p[1]);
wait(0);
read(p[0], &buf, 1);
close(p[0]);
printf("%d: received pong\n", getpid());
exit(0);
}
}
测试结果:
pingpong4.PNG
pingpong3.PNG
primes (hard)
使用多进程和管道,每个进程作为一个节点,筛掉某个素数的所有倍数
注意:关闭不用的管道。
#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
void primes(int p[2])
{
// 子进程只需要读,关闭写
close(p[1]);
int num;
read(p[0], &num, sizeof(num)); //读取第一个数
if (num == -1) {
exit(0);
}
printf("prime %d\n", num);
int p2[2];
pipe(p2); // 创建用于下一阶段的管道
if (fork() == 0) {
close(p[0]); // 关闭读
primes(p2);
} else {
close(p2[0]); // 主进程关闭读
int num2;
while (read(p[0], &num2, sizeof(num)) && num2 != -1) {
if (num2 % num != 0) {
write(p2[1], &num2, sizeof(num2));
}
}
num2 = -1;
write(p2[1], &num2, sizeof(num2));
wait(0);
exit(0);
}
}
int
main(int argc, char *argv[])
{
int p[2];
pipe(p);
if (fork() == 0) {
primes(p);
exit(0);
} else {
// 主进程只需要写,不需要读
close(p[0]);
int i;
for (i = 2; i <= 35; i++) { // 管道里写入2-35
write(p[1], &i, sizeof(i));
}
i = -1;
write(p[1], &i, sizeof(i));
close(p[1]); // 关闭写
wait(0);
}
exit(0);
}
测试结果:
primes1.PNG
primes2.PNG