【操作系统xv6】学习记录5--实验1 Lab: Xv6 and Unix utilities

ref:https://pdos.csail.mit.edu/6.828/2020/xv6.html

在这里插入图片描述

实验:Lab: Xv6 and Unix utilities

环境搭建

实验环境搭建:https://blog.csdn.net/qq_45512097/article/details/126741793
搭建了1天,大家自求多福吧,哎。~搞环境真是折磨人
anyway,我搞好了:
在这里插入图片描述

开整实验

内容1:sleep

创建user/sleep.c
在Makefile中UPROGS下添加$U/_sleep
编写sleep.c
运行测试程序grade-lab-util并且指明要测试的函数。如 grade-lab-util sleep

#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"void main(int argc, char *argv[])
{if(argc != 2){// 2 输出到哪里,输出内容,fprintf(2,"usage:sleep <time> \n");exit(1);}int sec = atoi(argv[1]);sleep(sec);  //printf("usage:sleep %d \n",sec);exit(0);
}

修改makefile,只需要改这一个地方

在这里插入图片描述

验证命令,要退出qume才能执行,否则会报错,
这种时候单项验证sleep

./grade-lab-util sleep
justin@DESKTOP-NIK28BI:~/vc6/xv6-labs-2020$ ./grade-lab-util sleep
fatal: detected dubious ownership in repository at '/mnt/d/code/vc6/xv6-labs-2020'
To add an exception for this directory, call:git config --global --add safe.directory /mnt/d/code/vc6/xv6-labs-2020
make: 'kernel/kernel' is up to date.
== Test sleep, no arguments == fatal: detected dubious ownership in repository at '/mnt/d/code/vc6/xv6-labs-2020'
To add an exception for this directory, call:git config --global --add safe.directory /mnt/d/code/vc6/xv6-labs-2020
sleep, no arguments: OK (1.3s)
== Test sleep, returns == sleep, returns: OK (0.8s)
== Test sleep, makes syscall == sleep, makes syscall: OK (1.0s)

内容2:pingpong

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.

#include "kernel/types.h"
#include "user/user.h"
#define RD 0 // pipe的read端
#define WR 1 // pipe的write端
int main(){char buf[10]; //缓冲区字符数组,存放传递的信息int fd_c2p[1]; // child->parentint fd_p2c[1]; // parent->childint ret1 = pipe(fd_c2p);int ret2 = pipe(fd_p2c);if(ret1==-1){printf("child->parent pipe");exit(1);}if(ret2==-1){printf("parent->child pipe");exit(1);}int pid = fork();if(pid==0){//子进程// 关闭父管道的写入端和子管道的读取端close(fd_p2c[WR]); // 显示关闭是为了严谨,不关闭不会报错close(fd_c2p[RD]); //read(fd_p2c[RD],buf,4);printf("child:%d received %s\n", getpid(),buf);write(fd_c2p[WR],"pong",4);}else if(pid>0){close(fd_p2c[RD]);close(fd_c2p[WR]);// 父进程write(fd_p2c[WR],"ping",4);int status;int child_id = wait(&status);printf("child:%d done!\n",child_id);read(fd_c2p[RD],buf,4);printf("parent:%d received %s\n", getpid(),buf);printf("parent:%d done!\n", getpid());}exit(0);return 0;
}

hart 1 starting
hart 2 starting
init: starting sh
$ pingpong
child:4 received ping
child:4 done!
parent:3 received pong
parent:3 done!

注意没有exit(0); 会出现乱码,原因未知,欢迎大神留言解惑:

hart 1 starting
hart 2 starting
init: starting sh
$ pingpong
child:4 received ping
usertrap(): unexpected scause 0x000000000000000d pid=4sepc=0x0000000000000100 stval=0x0000000000003f64
child:4 done!
parent:3 received pong
parent:3 done!
usertrap(): unexpected scause 0x000000000000000d pid=3sepc=0x0000000000000100 stval=0x0000000000003f64

内容3:Primes(素数,难度:Moderate/Hard)

YOUR JOB
使用管道编写prime sieve(筛选素数)的并发版本。这个想法是由Unix管道的发明者Doug McIlroy提出的。请查看这个网站(翻译在下面),该网页中间的图片和周围的文字解释了如何做到这一点。您的解决方案应该在user/primes.c文件中。

您的目标是使用pipe和fork来设置管道。第一个进程将数字2到35输入管道。对于每个素数,您将安排创建一个进程,该进程通过一个管道从其左邻居读取数据,并通过另一个管道向其右邻居写入数据。由于xv6的文件描述符和进程数量有限,因此第一个进程可以在35处停止。

提示:

  • 请仔细关闭进程不需要的文件描述符,否则您的程序将在第一个进程达到35之前就会导致xv6系统资源不足。
  • 一旦第一个进程达到35,它应该使用wait等待整个管道终止,包括所有子孙进程等等。因此,主primes进程应该只在打印完所有输出之后,并且在所有其他primes进程退出之后退出。
  • 提示:当管道的write端关闭时,read返回零。
  • 最简单的方法是直接将32位(4字节)int写入管道,而不是使用格式化的ASCII I/O。
  • 您应该仅在需要时在管线中创建进程。
  • 将程序添加到Makefile中的UPROGS。

如果您的解决方案实现了基于管道的筛选并产生以下输出,则是正确的:

$ 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
$

考虑所有小于1000的素数的生成。Eratosthenes的筛选法可以通过执行以下伪代码的进程管线来模拟:

p = get a number from left neighbor
print p
loop:n = get a number from left neighborif (p does not divide n)send n to right neighbor
p = 从左邻居中获取一个数
print p
loop:n = 从左邻居中获取一个数if (n不能被p整除)将n发送给右邻居

在这里插入图片描述
生成进程可以将数字2、3、4、…、1000输入管道的左端:行中的第一个进程消除2的倍数,第二个进程消除3的倍数,第三个进程消除5的倍数,依此类推。

这是我调试版本的代码,没有在xv6中打印,可以在任何linux中运行。
取数据:lpipe,写数据rpipe, 从图中可以看到,每个矩形的操作是重复的,所以应该用递归调用function primes,
而且每次递归调用,生成新的子进程,继续递归调用。

#include<unistd.h>
#include<stdlib.h>
#include<stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#define RD 0
#define WR 1
/*** @brief 寻找素数* @param lpipe 左邻居管道*/
void primes(int lpipe[2]){ //接收的参数当左通道用close(lpipe[WR]);int first;if(read(lpipe[RD],&first,sizeof(int))==sizeof(int)){ // 读到了【左管道】(第一次是main)送过来的数据printf("prime %d\n",first);printf("get first:%d\n",first);// 定义右管道int rpipe[2];pipe(rpipe); // 生成右管道,做数据过滤int data;while(read(lpipe[RD], &data, sizeof(int))==sizeof(int)){if (data % first){// 除尽的过滤掉,除不尽的留下,放到右管道 write(rpipe[WR], &data, sizeof(int));}}if (fork() == 0) {primes(rpipe);    // 递归的思想,但这将在一个新的进程中调用} else {close(rpipe[WR]);// 关闭右管道的写wait(0);//等待回收子进程}}}
int main(){int p[2];pipe(p);int res;for (size_t i = 2; i <= 35; i++){// 依次写入初始数据 2,3,4,...35res = write(p[WR],&i,sizeof(size_t));printf("pid:%d, send:%d, res:%d\n",getpid(),i,res);}if (fork()==0){   //子进程做筛选素数操作,是递归筛选primes(p); }else{//父进程啥也不干,等着回收子进程即可close(p[WR]); // 这里写关不关闭无所谓,但是谨慎起见,还是关闭为好close(p[RD]);//这里必须要关闭读,否则子进程无法从管道读取数据。wait(0);  }exit(0);  }

main函数的 close(p[RD]);//这里必须要关闭读,否则子进程无法从管道读取数据。
读操作只能确保开放给一个进程!这个题目是很难的!

4.find(难度:Moderate)

YOUR JOB

写一个简化版本的UNIX的find程序:查找目录树中具有特定名称的所有文件,你的解决方案应该放在user/find.c

在这里插入图片描述

5.xargs(难度:Moderate)

YOUR JOB

编写一个简化版UNIX的xargs程序:它从标准输入中按行读取,并且为每一行执行一个命令,将行作为参数提供给命令。你的解决方案应该在user/xargs.c

下面的例子解释了xargs的行为

$ echo hello too | xargs echo bye
bye hello too
$

注意,这里的命令是echo bye,额外的参数是hello too,这样就组成了命令echo bye hello too,此命令输出bye hello too

请注意,UNIX上的xargs进行了优化,一次可以向该命令提供更多的参数。 我们不需要您进行此优化。 要使UNIX上的xargs表现出本实验所实现的方式,请将-n选项设置为1。例如

$ echo "1\n2" | xargs -n 1 echo line
line 1
line 2
$

提示:

  • 使用fork和exec对每行输入调用命令,在父进程中使用wait等待子进程完成命令。
  • 要读取单个输入行,请一次读取一个字符,直到出现换行符(‘\n’)。
  • kernel/param.h声明MAXARG,如果需要声明argv数组,这可能很有用。
  • 将程序添加到Makefile中的UPROGS。
  • 对文件系统的更改会在qemu的运行过程中保持不变;要获得一个干净的文件系统,请运行make clean,然后make qemu
  • xargs、find和grep结合得很好

ref:https://xv6.dgs.zone/labs/requirements/lab1.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/327093.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Android取证篇】小米手机OTG取证知识

【Android取证篇】小米手机OTG取证知识 小米手机OTG使用方法—【蘇小沐】 目录 1、OTG用途 2、手机连不上U盘 3、小米手机有没有OTG 4、手机usb调试找不到 5、MHL能否在HDMI输出视频的同时进行USB传输 1、OTG用途 使用OTG外接设备&#xff0c;需要使用和手机接口对应匹配的…

计算机基础知识——校验码概述

目录 1 码距 2 奇偶校验 3 CRC循环冗余校验码 3.1 多项式 3.2 编码的组成 3.3 生成多项式 3.4 校验码的生成 4 海明校验码和恒比码 4.1 校验方程 4.2 恒比码 1 码距 码距是恒量一种编码方式的抗错误能力的一个指标。数字信息在传输和存取的过程中&#xff0c;由于…

C++补充内容--语法篇

这里写目录标题 语法其他语法函数的存储类函数参数默认值格式默认参数位置重载函数的默认参数 指针名与正常指针的自增自减以及解引用与的优先级问题指针的赋值、加减数字、加减指针二维数组中的一些指针辨析输出调用字符指针时 会将该指针以及之后的元素全部输出二维数组未完全…

栅极驱动芯片三种隔离技术

栅极驱动芯片三种隔离技术 1.栅极驱动器概述2.隔离栅极驱动芯片2.1隔离驱动器重要指标 3.三种常见隔离技术3.1光隔离3.2变压器隔离/磁隔3.3电容隔离 4.三种隔离器性能对比 1.栅极驱动器概述 栅极驱动器&#xff0c;在任何功率水平为任何应用高效可靠地驱动任何功率开关。 比如M…

Iceberg从入门到精通系列之十九:分区

Iceberg从入门到精通系列之十九&#xff1a;分区 一、认识分区二、Iceberg的分区三、Hive 中的分区四、Hive 分区问题五、Iceberg的隐藏分区六、分区变换七、分区变换 一、认识分区 分区是一种通过在写入时将相似的行分组在一起来加快查询速度的方法。 例如&#xff0c;从日志…

网络知识-以太网技术的发展及网络设备

目 录 一、背景介绍 &#xff08;一&#xff09;网络技术的时代 &#xff08;二&#xff09;以太网技术脱颖而出 二、以太网的工作原理 &#xff08;一&#xff09;、载波侦听多路访问&#xff08;CSMA/CD&#xff09; 1、数据发送流程 2、发送过程解析 3、…

Allegro如何进行四层板板层设计

Allegro如何进行四层板板层设计 板层设计说明 在进行多层板设计时我们画好PCB板框后&#xff0c;都要进行板层的设计。这里就以最简单的4层板为例为大家举例说明。 板层设置 点击“Setup”->“Cross Section Editor”如下图所示&#xff1a; 也可以直接点击工具栏进入…

手写视频裁剪框

<!-- 截取框 --><divv-show"isShow"class"crop-box":style"{width: cropWidth px,height: cropHeight px,left: cropX px,top: cropY px,}"ref"cropBox"mousedown"startInteraction"><!-- 内容在这里 --…

数据库选择题 (期末复习)

数据库第一章 概论简答题 数据库第二章 关系数据库简答题 数据库第三章 SQL简答题 数据库第四第五章 安全性和完整性简答题 数据库第七章 数据库设计简答题 数据库第九章 查询处理和优化简答题 数据库第十第十一章 恢复和并发简答题 2015期末 1、在数据库中&#xff0c;下列说…

分布式(6)

目录 26.雪花算法如何实现的&#xff1f; 27.雪花算法有什么问题&#xff1f;有哪些解决思路&#xff1f; 28.有哪些方案实现分布式锁&#xff1f; 29.基于数据库如何实现分布式锁&#xff1f;有什么缺陷&#xff1f; 30.基于Redis如何实现分布式锁&#xff1f;有什么缺陷&…

Unix操作系统的前世今生

Unix是一种多用户、多任务操作系统&#xff0c;最初由AT&T贝尔实验室的肯汤普逊&#xff08;Ken Thompson&#xff09;和丹尼斯里奇&#xff08;Dennis Ritchie&#xff09;等人开发于上世纪70年代初。它被设计成一种通用的操作系统&#xff0c;支持跨多种硬件平台&#xf…