lab1 utilities

在这里插入图片描述

测试和运行

参考大佬

  1. 修改grade-lab-util文件中的python为python3
  2. xv6.out这个文件的所有者可能是root,需要修改为用户,sudo chown woaixiaoxiao xv6.out
    每完成一个函数,执行下面的步骤
  3. 在Makefile中加入新增的程序$U/_sleep\
  4. make qemu,顺便可以自测一下命令是否有效
  5. ./grade-lab-util sleep

sleep


要求

  1. xv6实现sleep函数,用户可以指定暂停多少个tick
  2. user/sleep.c中实现,这个文件要自己创建

思路

  1. 首先根据argc和argv判断指令是否输入正确,并提取出sleep的tick数量
  2. 然后使用系统调用sleep函数
    1. 这里我一开始很疑惑,既然都有了一个sleep系统调用了,干嘛还要我们自己实现一个。
    2. 并且我发现只需要引用user/user.h头文件就可以使用这个系统调用,但是我没有发现user/user.c文件,目前我还看不太懂这个系统调用是如何实现的。
    3. 看了一些博客后,发现后面会讲,所以现在就把这些系统调用当做黑盒子来用就行了。
    4. 系统调用必须通过程序来使用的,也就是说就算我们有了sleep系统调用,但是我们依然需要写一个比如说c语言程序sleep来调用这个系统调用

注意点

  1. 头文件的顺序是有讲究的,因为user.h中使用了types.h中定义的变量,因此必须也包含types.h并且需要放到user.h前面

代码实现

#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"int main(int argc, char** argv) {if (argc < 2) {printf("usage: sleep time_val...\n");exit(1);}int tick = atoi(argv[1]);sleep(tick);exit(0);
}

pingpong


要求

  1. 在父子进程之间利用两个管道进行通信,每个管道负责一个方向
  2. 只需要传输一个字节的数据,父子进程在收到数据后应该打印信息
  3. 顺序上应该父进程先发送,子进程后发送

思路

  1. 按照题目要求的来就行了,顺序上通过read自带的阻塞就可以让子进程在收到父进程发送数据之后再发给父进程了

注意点

  1. 对于管道,可以看成是已经open的文件,不需要open,直接read和write
  2. read和write需要给出size,而c语言里的字符串往往是通过一个0来结尾的,那在调用read或者write时的size需要加上这个0吗?答案是不需要,只需要给出有效数据的size。而这个0只需要在我们创建buf数组的时候考虑即可
  3. 可以定义宏来表示0和1,这样在使用管道的时候更加清晰

实现

#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"#define SIZE 1int main() {// p1 父写子读int p1[2];pipe(p1);// p2 子写父读int p2[2];pipe(p2);// 子进程if (fork() == 0) {// 子进程阻塞p1的写端,p2的读端close(p1[1]);close(p2[0]);char buf[SIZE + 1];read(p1[0], buf, SIZE);printf("%d: received ping\n", getpid());write(p2[1], buf, SIZE);exit(0);} else {// 父进程close(p1[0]);close(p2[1]);char buf[SIZE] = "1";write(p1[1], buf, SIZE);read(p2[0], buf, SIZE);printf("%d: received pong\n", getpid());}exit(0);
}

primes


题意

  1. 要我们输出35以内的所有质数(实验文档给的参考资料是求1000以内的,但是好像因为xv6资源的限制,搞不了这么多,所以只需要求35以内的)
  2. 需要用到一种很神奇的方法
    1. 我们会用到很多进程,每个进程之间用一个管道相连接
    2. 每个进程会收到上一个进程发来的很多数字,其中第一个数字一定是质数,后面的数字有两种情况
      1. 如果是第一个数字的倍数,那肯定不是质数,不需要管了
      2. 如果不是第一个数字的倍数,则传给下一个进程,让下一个进程去处理

思路

  1. 解题的方法以及比较明确了,关键是如何实现这个过程?
  2. 我们最开始只有一个main进程,而我们需要很多的进程,并且这些进程之间是串联的,最重要的是逻辑都一样,所以可以用递归
  3. 这些进程是通过管道进行通信的,那么最简单的方法就是将管道作为递归函数的参数进行传递,这样就把所有的进程给串起来了

注意点

  1. 因为xv6的文件描述符是有限的,所以我们最好在能够关闭管道的时候都给它关了
  2. 在我的实现中,递归程序很早的就fork了,但是因为在fork之前先执行了一个read操作,因此,不会导致无限增殖,一个进程想要fork,起码也需要它获得了一个值

代码实现

#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"#define INT_SIZE 4
#define RD 0
#define WR 1
#define NULL 0void recursion(int p[]) {// 首先关闭写端close(p[WR]);// 读取base数字int base;int temp = read(p[RD], &base, INT_SIZE);// 压根没有输入到这个进程if (temp == 0) {return;}printf("prime %d\n", base);// 创建管道,并和子进程联动int p2[2];pipe(p2);if (fork() == 0) {recursion(p2);exit(0);}// 关闭读端close(p2[RD]);// 开始不断接受父进程的输入,判断之后传递给子进程int rec, res;while (1) {res = read(p[RD], &rec, INT_SIZE);// 父进程结束写了if (res == 0) {break;}// 如果这个数字不是base的倍数,那么写给子进程if (rec % base != 0) {write(p2[WR], &rec, INT_SIZE);}}// 写完了,关闭自己的写端close(p2[WR]);// 关闭父进程给的管道的读端close(p[RD]);wait(NULL);
}int main() {int p[2];pipe(p);// 子进程if (fork() == 0) {recursion(p);exit(0);}// 父进程close(p[RD]);for (int i = 2;i <= 35;i++) {write(p[WR], &i, INT_SIZE);}close(p[WR]);// 等待子进程结束wait(NULL);exit(0);
}

find


题意

  1. 实现find指令,find dir filename的作用是找到dir目录中(包括所有子目录中),所有文件名为filename的文件
  2. 因此,我们要做的就是取出dir目录的每一项,如果是文件,那就比较这个文件的名称,如果是目录,那我们就递归进去

思路

  1. hints里提示我们去看ls.c文件是如何访问目录的
    1. 首先,我们需要根据目录的路径打开目录。目录也是一个文件,所以方法和打开普通的文件一样,并且得到一个文件描述符
    2. 通过文件描述符去read,但是这个时候要用dirent这个结构去读取每一个目录项
    3. 通过direntname以及当前目录的path,可以构造出这个目录项的path
    4. 通过这个目录项的pathstat函数,可以把这个目录项的信息给读到stat结构中
    5. 通过stat结构体的type可以区分目录和文件
      1. 文件则直接比较名字
      2. 目录如果不是...,那就递归进去

注意点

  1. 打开的文件描述符最好自己记得把它给关了

实现代码

#include "kernel/types.h"
#include "kernel/stat.h"
#include "kernel/fs.h"
#include "user/user.h"#define O_RDONLY 0
#define MAX_PATH 512void search(char* dir, char* filename) {// 获取当前目录的文件描述符int fd = open(dir, O_RDONLY);// 不断读取目录项,进行判断// 这个p是用来拼接这个目录中的子项的路径的char buf[MAX_PATH];strcpy(buf, dir);char* p = buf + strlen(buf);*p = '/';p++;// 正式读取每一行,并根据目录还是文件进行讨论struct dirent de;struct stat st;while (read(fd, &de, sizeof(de)) == sizeof(de)) {// 无效if (de.inum == 0) {continue;}// 拼接出目录的这一项的pathmemmove(p, de.name, DIRSIZ);p[DIRSIZ] = 0;// 取出这一项的信息stat(buf, &st);// 如果是文件if (st.type == T_FILE) {// 文件名相同,打印pathif (strcmp(de.name, filename) == 0) {printf("%s\n", buf);}} else if (st.type == T_DIR) {// 这一项是目录,只要不是 . 或者 .. 那就递归进去if (strcmp(de.name, ".") != 0 && strcmp(de.name, "..") != 0) {search(buf, filename);}}}// 记得关闭文件描述符close(fd);
}int main(int argc, char** argv) {if (argc != 3) {printf("usage: find dir filename\n");exit(1);}char* dir = argv[1];char* filename = argv[2];search(dir, filename);exit(0);
}

xargs


题意

  1. 实现xargs函数,xargs a b代表执行a程序,a程序的第一个参数是bxargs会从标准输入中按行读取,将每一行作为a的其他参数,假如读入了某一行是c d,那么说明a程序有三个参数,依次是b c d
  2. xargs按行读取的意思是,对于每一行,它都会读取这一行所有被空格分开的值,将它作为a程序的参数。假如有n行,就会执行na程序
  3. 实验文档里给的示例echo hello too | xargs echo bye
    1. 这里面|的作用是把它前面的运行结果给放到后面这个函数的标准输入中
    2. 在这个例子里,就是把hello too作为一行放到了xargs函数的标准输入里,也就是说,如果xargs能够调用scanf函数,就可以读到hello too

思路

  1. 从标准输入中不断地读取,以每一行为单位进行fork和exec
  2. 每一行以\n为结束符,实验文档推荐我们每一次读一个字节,这样比较好判断\n,可以通过read函数实现读取
  3. 读取的每个字节有三种情况
    1. 是空格,则说明空格前那个参数已经被读取完了,加入到之后要调用的exec函数的args数组中
    2. 是换行符,首先也要加入前面的参数,然后记得给args数组封尾,即放一个null在最后,之后fork,exec,并进入新一行的读取
  4. 如果read失败,说明读完了,跳出整个循环,wait等到所有子进程结束

注意点

  1. 我们不断从标准输入中读取,其实就是为了给exec函数准备参数数组,这里用args表示,一开始xargs的main函数的argv数组就包括了要执行的程序的一些信息,所以应该将其挪到args数组中
  2. 当我们成功从某一行中读取一个参数的时候,这里是把这个参数边读边存到input_line字符串中,不能直接将这个字符串放到args数组,因为这个字符串被重复使用,所以我们要进行深拷贝,这里手写了一个strdup函数完成这个效果
  3. 然后就是注意各种字符串的操作,要给它封住尾巴
  4. 最后通过这个操作等待所有子进程结束while (wait(0) != -1)

实现代码

#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
#include "kernel/param.h"#define stdin 0
#define NULL 0
#define MAX_SIZE 1024
#define CHAR_SIZE 1char* strdup(char* p) {char* temp = (char*)malloc(strlen(p) + 1);memcpy(temp, p, strlen(p));return temp;
}int main(int argc, char* argv[]) {// 初始化我们要传递给execute函数的参数char* args[MAXARG + 2];for (int i = 1;i < argc;i++) {args[i - 1] = argv[i];}int arg_count = argc - 1;// 从标准输入一行一行地读char input_line[MAX_SIZE];while (1) {// 最外层的这个while循环,每循环一次代表要execute一次// 因此arg_count和p都应该重置,其中p用来操作input_linearg_count = argc - 1;char* p = input_line;// 用read从标准输入端读int res;while ((res = read(stdin, p, CHAR_SIZE)) > 0) {// 如果读入的既不是空格也不是换行,那就让p++,继续读入这个参数if (*p != ' ' && *p != '\n') {p++;// 读入的是空格,说明第一个参数已经完成了// 那么我们可以将这个参数写入args,并且修改p指针} else if (*p == ' ') {*p = '\0';args[arg_count] = strdup(input_line);arg_count++;p = input_line;// 读入的是换行,说明已经完全读完了// 存当前的这个参数到args,并且为args增加一个结尾标志null// 然后fork,exec} else if (*p == '\n') {*p = '\0';args[arg_count] = strdup(input_line);arg_count++;args[arg_count] = NULL;// 子进程,去execif (fork() == 0) {exec(args[0], args);exit(0);}// 父进程,现在应该去读新的一行了,breakbreak;}}// 读完了if (res <= 0) {break;}}// 等待所有子进程结束while (wait(0) != -1) {}exit(0);
}

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

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

相关文章

linux 命令- systemctl

systemctl 参数说明 1、使用语法 用法&#xff1a;systemctl [OPTIONS…] {COMMAND} … 2 、参数说明 参数参数说明start立刻启动后面接的unitstop立刻关闭后面接的unitrestart立刻关闭后启动后面接的unit&#xff0c;亦即执行stop再start的意思reload不关闭后面接的unit的…

PyTorch深度学习环境安装(Anaconda、CUDA、cuDNN)及关联PyCharm

1. 关系讲解 Tytorch&#xff1a;Python机器学习库&#xff0c;基于Torch&#xff0c;用于自然语言处理等应用程序 Anaconda&#xff1a;是默认的python包和环境管理工具&#xff0c;安装了anaconda&#xff0c;就默认安装了conda CUDA&#xff1a;CUDA是一种由显卡厂商NVIDI…

取个对象值导致系统崩溃

取个对象值导致系统崩溃 前言 想必各位小伙经常在项目中遇到一些错误&#xff0c;取对象值的时候&#xff0c;经常报错,又或者某些项目突然就挂经常都是出现在一些对象取值上面&#xff0c;然后就被领导一顿训斥 报错分析 例如&#xff1a; 下面这个报错大家想必不会陌生&am…

后端开发8.品牌模块

概述 简介 效果图 数据库设计 DROP TABLE IF EXISTS `goods_brand`;CREATE TABLE `goods_brand` ( `goodsBrandId` int(11) NOT NULL AUTO_IN

浅谈机器人流程自动化(RPA)

1.什么是RPA RPA代表机器人流程自动化&#xff08;Robotic Process Automation&#xff09;&#xff0c;是一种利用软件机器人或机器人工作流程来执行重复性、规范性和高度可预测性的业务流程的技术。这些流程通常涉及许多繁琐的、重复的任务&#xff0c;例如数据输入、数据处…

系统架构设计专业技能 · 网络规划与设计(三)【系统架构设计师】

系列文章目录 系统架构设计专业技能 网络规划与设计&#xff08;三&#xff09;【系统架构设计师】 系统架构设计专业技能 系统安全分析与设计&#xff08;四&#xff09;【系统架构设计师】 系统架构设计高级技能 软件架构设计&#xff08;一&#xff09;【系统架构设计师…

0基础学习VR全景平台篇 第79篇:全景相机-泰科易如何直播推流

泰科易科技是中国的一家研发全景相机的高科技公司&#xff0c;前不久&#xff0c;在2020世界VR产业大会上发布了新一代5G VR直播影像采集终端--360starlight。以其出色的夜景成像效果和一“部”到位的直播方案重新定义了VR慢直播相机&#xff0c;对行业具有高度借鉴意义。 本文…

Uniapp使用腾讯地图并进行标点创建和设置保姆教程

使用Uniapp内置地图 首先我们需要创建一个uniapp项目 首先我们需要创建一个uniapp项目 我们在HBuilder左上角点击文件新建创建一个项目 然后下面这张图的话就是uniapp创建项目过程当中需要注意的一些点和具体的操作 然后我们创建完项目之后进入到项目pages文件夹下&#xff…

【学习FreeRTOS】第2章——FreeRTOS基础知识

1.任务调度 1.1.任务调度简介 调度器就是使用相关的调度算法来决定当前需要执行的哪个任务FreeRTOS 一共支持三种任务调度方式&#xff1a; 抢占式调度&#xff1a;针对优先级不同的任务&#xff0c;每个任务都有一个优先级&#xff0c;优先级高的任务可以抢占优先级低的任务…

Webstorm + Egg.js 进行断点调试

Webstorm Egg.js 进行断点调试 1、在工具栏找到编辑配置&#xff0c;创建已运行Node.js 应用程序的调试配置 2、debug调试配置 3、调试 4、查看断点是否起效

python爬虫相关

目录 初识爬虫 爬虫分类 网络爬虫原理 爬虫基本工作流程 搜索引擎获取新网站的url robots.txt HTHP协议 Resquests模块 前言&#xff1a; 安装 普通请求 会话请求 response的常用方法 简单案例 aiohttp模块 使用前安装模块 具体案例 数据解析 re解析 bs4…

计算机竞赛 opencv python 深度学习垃圾图像分类系统

0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; opencv python 深度学习垃圾分类系统 &#x1f947;学长这里给一个题目综合评分(每项满分5分) 难度系数&#xff1a;3分工作量&#xff1a;3分创新点&#xff1a;4分 这是一个较为新颖的竞…

WebStorm

WebStorm 介绍下载安装Activation 介绍 WebStorm是由JetBrains公司开发的一款集成开发环境&#xff08;IDE&#xff09;&#xff0c;主要专注于前端开发和Web开发。它旨在提供一套强大的工具和功能&#xff0c;以支持开发者在前端项目中编写、调试和维护代码。 JetBrains官网: …

keil下载程序具体过程2:硬件链路

引言 本篇博客将介绍keil下载程序的过程中&#xff0c;镜像文件将经过哪些硬件&#xff0c;以及简单的介绍他们之间的协议。 一、硬件连接 图1 硬件连接 将PC、jlink、芯片使用ubs线、swd线连接好之后&#xff0c;在PC上的keil软件中&#xff0c;我们选择对应的仿真器&#xf…

【算法题】螺旋矩阵II (求解n阶Z形矩阵)

一、问题的提出 n阶Z形矩阵的特点是按照之(Z)字形的方式排列元素。n阶Z形矩阵是指矩阵的大小为nn&#xff0c;其中n为正整数。 题目描述 一个 n 行 n 列的螺旋(Z形)矩阵如图1所示&#xff0c;观察并找出填数规律。 图1 7行7列和8行8列的螺旋(Z形)矩阵 现在给出矩阵大小 n&…

SDR硬件方案

以射频硬件为线索&#xff0c;梳理常见SDR&#xff08;软件无线电&#xff09;方案。SDR硬件位于天线和数字信号处理之间&#xff0c;负责把无线电信号数字化&#xff0c;交由主机或者嵌入式系统&#xff08;FPGA、DSP&#xff0c;MCU&#xff09;处理。SDR硬件一般包含射频和数…

题解:ABC276E - Round Trip

题解&#xff1a;ABC276E - Round Trip 题目 链接&#xff1a;Atcoder。 链接&#xff1a;洛谷。 难度 算法难度&#xff1a;普及。 思维难度&#xff1a;提高。 调码难度&#xff1a;提高。 综合评价&#xff1a;困难。 算法 bfs。 思路 从起点周围四个点中任选两…

C语言 ——指针数组与数组指针

目录 一、二维数组 二、指针数组 &#xff08;1&#xff09;概念 &#xff08;2&#xff09;书写方式 &#xff08;3&#xff09;指针数组模拟二维数组 三、数组指针 &#xff08;1&#xff09;概念 &#xff08;2&#xff09;使用数组指针打印一维数组 &#xff08;3&a…

使用sqlplus连接oracle,提示ORA-01034和ORA-27101

具体内容如下 PL/SQL Developer 处 登录时 终端处 登录时 ERROR: ORA-01034: ORACLE not available ORA-27101: shared memory realm does not exist Process ID: 0 Session ID: 0 Serial number: 0 解决方法是执行以下命令 sqlplus /nolog conn / as sysdba startup …

Android APK体积优化(瘦身)

1、基础知识&#xff1a; 1.1 apk结构 lib &#xff1a;存放so文件&#xff0c;对应不同的cpu架构 res &#xff1a;资源文件&#xff0c;layout、drawable等&#xff0c;经过aapt编译 assets &#xff1a;资源文件&#xff0c;不经过aapt编译 classes.dex &#xff1a;dx编译…