MIT 6.S081 lab1

一、安装环境

我使用的Ubuntu22.04。

//安装必须的工具链

sudo apt-get install git build-essential gdb-multiarch qemu-system-misc gcc-riscv64-linux-gnu binutils-riscv64-linux-gnu

//单独移除掉qemu的新版本

sudo apt-get remove qemu-system-misc

//额外安装一个旧版本qemu

wget https://download.qemu.org/qemu-5.1.0.tar.xz

tar xf qemu-5.1.0.tar.xz

cd qemu-5.1.0

./configure --disable-kvm --disable-werror --prefix=/usr/local --target-list="riscv64-softmmu"

make

sudo make install

//克隆xv6仓库

git clone git://g.csail.mit.edu/xv6-labs-2020

cd xv6-labs-2020

git checkout util

//进行编译

make qemu

//编译成功并进入xv6操作系统的shell

xv6 kernel is booting

hart 2 starting
hart 1 starting
init: starting sh
输入ls指令

.              1 1 1024
..             1 1 1024
README         2 2 2059
xargstest.sh   2 3 93
cat            2 4 23688
echo           2 5 22512
forktest       2 6 13256
grep           2 7 26832
init           2 8 23336
kill           2 9 22456
ln             2 10 22304
ls             2 11 25856
mkdir          2 12 22576
rm             2 13 22560
sh             2 14 40584
stressfs       2 15 23552
usertests      2 16 142288
grind          2 17 36968
wc             2 18 24656
zombie         2 19 21832
sleep          2 20 22344
pingpong       2 21 23648
primes         2 22 24104
find           2 23 26160
xargs          2 24 24488
console        3 25 0

在安装的过程中,可能出现缺少某些包,百度后直接安装即可。

二、sleep

实现xv6的UNIX程序sleep,你的睡眠程序应该暂停一段用户指定的ticks,tick是xv6内核定义的时间概念,即来自定时器的两次中断之间的时间差。你的解决方案应在user/sleep.c中。

这个只需要调用sleep()即可。

#include "kernel/types.h"
#include "user/user.h"
int main(int argc, char *argv[]){
	if(argc != 2){
		fprintf(2,"usage sleep\n");
		exit(1);
	}
	int ticks = atoi(argv[1]);
	int ret = sleep(ticks);
	exit(ret);
}

写好之后,在Makefile中的UPROGS后面添加即可,MakeFile在xv6-labs-2020目录下,可以会隐藏,ls -l可以看到,直接vim对其操作即可。注意后面不要加空格,否则会报错。

最后测试结果如下

三、pingpong

编写一个程序,使用UNIX系统调用在一对管道上的两个进程之间“pingpiong”的一个字节,每个方向上一个。父进程应向子进程发送一个字节;子进程打印出其pid:received ping,之后将管道上的字节写入父进程,父进程打印出pid:received pong,然后退出。你的解决方案应在文件user/pingpong中。

创建

#include "kernel/types.h"
#include "user/user.h"

int main(int argc,char *argv[]){
	int fd_1[2],fd_2[2];
	int pid;
	char buf = 'A';
	char receiveBuf;
	if(pipe(fd_1) < 0){
		fprintf(2,"creat pipe error");
		exit(1);
	}
	if(pipe(fd_2) < 0){
		fprintf(2,"creat pipe error");
                exit(1);
	}
	pid = fork();
	if(pid == 0){
		close(fd_1[1]);
		close(fd_2[0]);
		read(fd_1[0],&receiveBuf,1);
		printf("%d: received ping\n",getpid());
		write(fd_2[1],&receiveBuf,1);
		close(fd_1[0]);
		close(fd_2[1]);
	
	}
	else if(pid > 0){
		close(fd_1[0]);
		close(fd_2[1]);
		write(fd_1[1],&buf,1);
		read(fd_2[0],&buf,1);
		printf("%d: received pong\n",getpid());
		close(fd_1[1]);
		close(fd_2[0]);
		
	}
	else{
		fprintf(2,"fork error");
	}
		exit(0);
}

两个管道,一个用于父进程向子进程发送数据,一个用于子进程向父进程发送数据。在不用管道哪个口时及时将其关闭。

注意:receive ping不要拼写错误,要不然测试不通过,而且ping的P也不能大写。

测试结果如下:

四、primes

使用管道编写primes sieve,这个想法要归功于Unix管道的发明者Doug McIlroy。本页下半部分的图片和周围的文字解释了如何做到这一点。您的解决方案应该在文件user/primes.c中。

你的目标是通过pipe和fork来设置管道。第一个进程将2-35送入到管道中。对于每个素数,创建一个进程,该进程从上一个进程中读取到数据,并通过另一个管道向下一个进程中写入数据。由于xv6具有有限数量的文件描述符和pid,因此第一个进程在35停止。

这道题目的意思可以很好的用这张图来表示。

即输入2-35,第一个进程首先从管道中读取,然后判读是不是第一个素数(也就是2)的倍数,将不是2的倍数的写入管道中,交给下一个进程,然后下一个进程判断是不是传入到这个进程第一个数(也就是3)的倍数。如此循环往复,直到数据判断完毕。由于每一个进程执行的过程都是读、判断、写的过程,因此使用递归。递归要注意递归的三要素,功能,结束条件,和等价调用。功能自然就是判断一个数是不是素数,结束条件是官道镇是否有数据,等价调用就是读、判断、写。

还有一个要注意的点的read()在读取管道的时候,在管道开启,管道中没有数据情况下,read()会阻塞;在管道已关闭,管道中没有数据的情况下,read()会返回0。

程序如下:

#include "kernel/types.h"
#include "user/user.h"


int recur(int pass);

int main(int argc, char **argv){
	int fd[2];
	if(pipe(fd) < 0){
		fprintf(2, "pipe error\n");
        exit(1);
	}

	int pid = fork();
	if(pid == 0){
		close(fd[1]);
		recur(fd[0]);
	}
	else if(pid > 0){
		close(fd[0]);
		for(int i = 2; i <= 35; i++){
			write(fd[1], &i, 4);
		}
		
		close(fd[1]);
		wait(0);//等待子进程退出
	}
	else{
		fprintf(2, "fork error\n");
        exit(1);
	}
	exit(0);
}
int recur(int pass){
	int f[2];
	int readBuf;
	int primes;
	if(read(pass,&readBuf,4) == 0){//管道中数据读取完毕
		close(pass);	
	}
	else{
		primes = readBuf;
		printf("prime %d\n", primes);
		pipe(f);
		int pid = fork();
		if(pid == 0){
			close(f[1]);
            recur(f[0]);
        }
		else if(pid > 0){
			close(f[0]);
			while((read(pass,&readBuf,4))){//判断数据是否读完,读完后,由于管道关闭,会返回0
				if(readBuf % primes != 0){//判断是否是第一个数的倍数
					write(f[1],&readBuf,4);	
				}		
		}
		close(f[1]);//关闭写管道
		wait(0);//等待子进程退出
	}
	}
	exit(0);
}

测试结果如下:

后面两个明天写。

  • 23
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值