操作系统入门系列-MIT6.828(操作系统工程)学习笔记(三)---- xv6初探与实验一(Lab: Xv6 and Unix utilities)

系列文章目录

操作系统入门系列-MIT6.S081(操作系统)学习笔记(一)---- 操作系统介绍与接口示例
操作系统入门系列-MIT6.828(操作系统工程)学习笔记(二)----课程实验环境搭建(wsl2+ubuntu+quem+xv6)
操作系统入门系列-MIT6.828(操作系统工程)学习笔记(三)---- xv6初探与实验一(Lab: Xv6 and Unix utilities)


文章目录

  • 系列文章目录
  • 前言
  • 一、xv6文档第一章
    • 1. 引论
  • 二、实验一
    • 1.启动xv6
    • 2.实现休眠函数
    • 3.实现父子进程pingpong打印
    • 4.使用pipeline实现质数检测
    • 5.实现find函数(文件查找)
    • 6.实现xargs函数
  • 总结


前言

MIT 6.828课程资料与进度计划表
完成第一节课的学习后,按照课程的计划进度表,应当阅读xv6文档的第一章节,以及完成实验1。
本文主要内容就是对xv6文档(2023年版)和实验(2023年版)的讲解
xv6英文文档—2023
xv6中文文档—2013
xv6实验1原文


一、xv6文档第一章

1. 引论

xv6操作系统提供 Unix 操作系统中的基本接口(由 Ken Thompson 和 Dennis Ritchie 引入),同时模仿 Unix 的内部设计,包括 BSD,Linux,Mac OS X,Solaris (甚至 Microsoft Windows 在某种程度上)都有类似 Unix 的接口,理解 xv6 是理解这些操作系统的一个良好起点。
首先需要对操作系统有一个系统结构的大致概念,如下图:
在这里插入图片描述
如图所示,操作系统的核心就是kernel。kernel起到了桥梁的作用,连接各种应用程序和底层硬件资源。从软件编程者的角度来看,程序员就是使用各种kernel提供的系统调用函数,来实现各种各样的功能。xv6的系统调用函数如下图所示:
在这里插入图片描述
后面的实验就是需要调用这些系统调用函数来实现相应的功能,比如在Linux里面常用的find、xargs等命令的简易版。
在之前的文章中已经将第一章的部分进行了讲解,详情见:
操作系统入门系列-MIT6.S081(操作系统)学习笔记(一)---- 操作系统介绍与接口示例

二、实验一

1.启动xv6

详见xv6环境的配置和启动
操作系统入门系列-MIT6.828(操作系统工程)学习笔记(二)----课程实验环境搭建(wsl2+ubuntu+quem+xv6)
(1)实验系统目录:
整个实验代码的文件目录如下,我们需要关注:

1.绿色的”grade-lab-util“可执行文件,它是测试机,用来测试你的实验代码正确性。
2.kernel文件夹,是xv6的kernel代码
3.Makefile是用来编译内核的,需要在这里添加参数,我们写的实验代码才能编译进去
4.user文件夹是我们添加自己实验代码的地方,也就是用户空间	

在这里插入图片描述
(2)Makefile添加文件
在这里插入图片描述
(3)退出xv6
使用”ctrl+a“,后按x退出
(4)测试机打分
需要在lab目录中添加time.txt文件,里面写一个整数,代表你的实验花了多少小时。
在这里插入图片描述

2.实现休眠函数

(1)原题如下:
在这里插入图片描述
(2)大致内容为:
调用“系统调用函数——sleep()”(一次sleep()系统暂停一个tick),实现输入数字,系统暂停该数字次数的ticks。
参数错误时,要有错误打印
(3)代码如下:

// 参考echo.c、grep.c、rm.c的头文件引用
#include "kernel/types.h"//声明数据类型
#include "kernel/stat.h"//声明文件数据结构
#include "kernel/fcntl.h"//open函数的模式参数申明
#include "user/user.h"//声明各种系统调用函数、以及有用的库函数int main(int argc, char *argv[])
{int number;//参数数量不对,打印错误信息//参数还有其他错误情况,此处仅考虑数量问题if(argc <= 1){fprintf(2, "usage: sleep number\n");exit(1);}number = atoi(argv[1]);//字符串转整数sleep(number);//系统调用exit(0);
}

(4)结果如下:
使用官方提供的测试机程序,在lab目录下面运行"./grade-lab-util + 文件名"

./grade-lab-util sleep

测试机自主进行测试,如下图:
在这里插入图片描述
(5)总结:
在做实验之前我们需要知道有哪些函数我们是可以调用的,可以查看文件:“user/user.h”

struct stat;// system calls
int fork(void);
int exit(int) __attribute__((noreturn));
int wait(int*);
int pipe(int*);
int write(int, const void*, int);
int read(int, void*, int);
int close(int);
int kill(int);
int exec(const char*, char**);
int open(const char*, int);
int mknod(const char*, short, short);
int unlink(const char*);
int fstat(int fd, struct stat*);
int link(const char*, const char*);
int mkdir(const char*);
int chdir(const char*);
int dup(int);
int getpid(void);
char* sbrk(int);
int sleep(int);
int uptime(void);// ulib.c
int stat(const char*, struct stat*);
char* strcpy(char*, const char*);
void *memmove(void*, const void*, int);
char* strchr(const char*, char c);
int strcmp(const char*, const char*);
void fprintf(int, const char*, ...);
void printf(const char*, ...);
char* gets(char*, int max);
uint strlen(const char*);
void* memset(void*, int, uint);
void* malloc(uint);
void free(void*);
int atoi(const char*);
int memcmp(const void *, const void *, uint);
void *memcpy(void *, const void *, uint);

3.实现父子进程pingpong打印

(1)原题如下:
在这里插入图片描述
(2)大致内容为:
实现过程:父进程向子进程发送ping,子进程打印该信息,后子进程向父进程发送pong,父进程再打印该信息
实现结果为:
在这里插入图片描述

(3)代码如下:
分为单管道实现和双管道实现
单管道实现:

#include "kernel/types.h"
#include "kernel/stat.h"
#include "kernel/fcntl.h"
#include "user/user.h"int main(int argc, char *argv[])
{int p[2];char buf[512];//用来接收信息的bufferpipe(p);//父 <=======> 子//子进程执行if,父进程执行elseif(fork() == 0){read(p[0], buf, sizeof(buf));//阻塞,直到父进程写入管道p内容,后读取父进程的信息fprintf(1,"%d: received %s\n", getpid(), buf);//打印父进程的信息write(p[1], "pong", 5);//使用p的写通道向父进程发送信息close(p[0]);//关闭读通道close(p[1]);//关闭写通道exit(0);//子进程退出}else{write(p[1], "ping", 5);//父进程通过p的写通道向子进程发送信息wait((int *)0);//等待子进程结束read(p[0], buf, sizeof(buf));//读取p管道中子进程的信息fprintf(1,"%d: received %s\n", getpid(), buf);//打印子进程的信息close(p[0]);//关闭读通道close(p[1]);//关闭写通道}exit(0);
}

双管道实现:

#include "kernel/types.h"
#include "kernel/stat.h"
#include "kernel/fcntl.h"
#include "user/user.h"int main(int argc, char *argv[])
{int p[2];int p2[2];char buf[512];//用来接收信息的buffer//向内核申请两个管道pipe(p);//父进程写,子进程读:父 ——————> 子pipe(p2);//子进程写,父进程读:子 ——————> 父//子进程执行if,父进程执行elseif(fork() == 0){close(p[1]);//关闭p的写通道,以便于父进程写完可以直接读取read(p[0], buf, sizeof(buf));//阻塞,直到父进程写入管道p内容,后读取父进程的信息fprintf(1,"%d: received %s\n", getpid(), buf);//打印父进程的信息close(p[0]);//关闭p的读通道write(p2[1], "pong", 5);//使用p2的写通道向父进程发送信息close(p2[1]);//写完关闭写通道close(p2[0]);//关闭p2的读通道exit(0);//子进程退出}else{write(p[1], "ping", 5);//父进程通过p的写通道向子进程发送信息close(p[1]);//写完关闭写通道close(p2[1]);//关闭p2的写通道,以便于子进程写完可以直接读取read(p2[0], buf, sizeof(buf));//阻塞,直到子进程写入管道p2内容,读取子进程的信息fprintf(1,"%d: received %s\n", getpid(), buf);//打印子进程的信息close(p[0]);//关闭p的读通道close(p2[0]);//关闭p2的读通道}exit(0);//结束程序
}

(4)结果如下:
在这里插入图片描述
(5)总结:

4.使用pipeline实现质数检测

(1)原题如下:
在这里插入图片描述
(2)大致内容为:
使用pipeline+多进程来检测35以内的质数检测
这个过程比较难想,但是在纸上推演一下流程就懂了,参考文献如下:Bell Labs and CSP Threads

参考伪代码:
在这里插入图片描述
参考图:
在这里插入图片描述
(3)代码如下:

#include "kernel/types.h"
#include "kernel/stat.h"
#include "kernel/fcntl.h"
#include "user/user.h"void child(int * p)
{int p1[2];char num[35];int prime;int i;int ret;int number;pipe(p1);close(p[1]);number = 0;for(i=0;i<35;i++){ret = read(p[0], num+i, 1);if(ret == 0){break;}number++;}if(number == 0){exit(0);}prime = num[0];printf("prime %d\n", prime);close(p[0]);if(fork() == 0){child(p1);}else{close(p1[0]);for(i=1;i<number;i++){if((num[i]%prime)!=0){write(p1[1], num+i, 1);}}close(p1[1]);wait((int *)0);}exit(0);
}int main()
{int prime = 2;int p[2];int i;pipe(p);if(fork() == 0){child(p);}else{close(p[0]);printf("prime %d\n", prime);for(i=3;i<=35;i++){if((i%prime)!=0){write(p[1], &i, 1);}}close(p[1]);wait((int *)0);}exit(0);
}

(4)结果如下:
在这里插入图片描述
在这里插入图片描述
(5)总结:
核心是算法题,载体是进程树之间使用pipeline进行读写控制

5.实现find函数(文件查找)

(1)原题如下:
在这里插入图片描述
(2)大致内容为:
实现目录下搜索文件的功能,要求能够找到该文件夹目录下以及其子目录下的指定文件名,输出所有满足文件的路径。(不要求实现正则表达式)(!!!记得规避".“与”…"子文件)(如何访问文件夹可以参考文件ls.c的实现)

  "  .  "  表示当前目录"  ..  "  表示当前目录的上一级目录。"  ./  "  表示当前目录下的某个文件或文件夹,视后面跟着的名字而定"  ../  "   表示当前目录上一级目录的文件或文件夹,视后面跟着的名字而定。

在这里插入图片描述
(3)代码如下:

#include "kernel/types.h"
#include "kernel/stat.h"
#include "kernel/fcntl.h"
#include "kernel/fs.h"
#include "user/user.h"char* fmtname(char *path)
{char *p;// Find first character after last slash.for(p=path+strlen(path); p >= path && *p != '/'; p--);p++;return p;
}int find(char *name, char *p)
{int fd;int path=0;char buf[512];struct dirent de;struct stat st;fd = open(p, O_RDONLY);if(fd < 0){fprintf(2, "fd: can not open %s\n");exit(1);}strcpy(buf, p);p = buf+strlen(buf);*p++ = '/';// printf("%d  %s\n", fd, buf);while(read(fd, &de, sizeof(de)) == sizeof(de)){if(de.inum == 0){continue;}memmove(p, de.name, DIRSIZ);p[DIRSIZ] = 0;// printf("%s\n", p);if(stat(buf, &st) < 0){printf("ls: cannot stat %s\n", buf);continue;}// printf("%s %s %d\n", buf, fmtname(buf), st.type);// printf("%d %d %d\n", strcmp(fmtname(buf), name), strcmp(fmtname(buf), "."), strcmp(".", "."));if (st.type == T_FILE && (strcmp(fmtname(buf), name) == 0)){printf("%s\n", buf);path = 1;} if (st.type == T_DIR && (strcmp(fmtname(buf), ".") != 0) && (strcmp(fmtname(buf), "..") != 0)){path = find(name, buf);}   }return path;
}int main(int argc, char *argv[])
{int path;if(argc < 3){fprintf(2, "fd: find [dir] [filename]\n");exit(1);}path = find(argv[2], argv[1]);if(path == 0){fprintf(1, "can not find such file\n");}exit(0);
}

(4)结果如下:
在这里插入图片描述
(5)总结:
核心知识点是xv6系统下的文件结构体与文件夹结构体,使用递归方法进行实现。

6.实现xargs函数

(1)原题如下:
在这里插入图片描述
(2)大致内容为:
实现xargs命令,xargs命令很难简单理解,建议先查一下命令的用法。
xargs 命令教程
(3)代码如下:

#include "kernel/types.h"
#include "kernel/stat.h"
#include "kernel/fcntl.h"
#include "user/user.h"
#include "kernel/param.h"int getcmd(char *buf, char**arg, int arg_num)
{int i;int j;j = 0;arg[arg_num] = (char *)malloc(30 * sizeof(char));for(i=0; i<512; i++){if((buf[i] == ' ') || (buf[i] == 10) || (buf[i] == '\0') || (buf[i] == '\n')){// printf("%c %d\n", buf[i], buf[i]);arg_num++;if(buf[i] == 10){// printf("argmun: %d\n", arg_num);return arg_num;}if(buf[i] == '\0'){// printf("argmun: %d\n", arg_num);return arg_num;}arg[arg_num] = (char *)malloc(30 * sizeof(char));// printf("111\n");// printf("%s %p kkk\n", arg[arg_num], arg[arg_num]);j = 0;}else{// printf("%d %d %c %d\n", j, i, buf[i], arg[arg_num][j]);arg[arg_num][j] = buf[i];// printf("%d %c \n", j, arg[arg_num][j]);j++;}}return arg_num;
}int main(int argc, char *argv[])
{char buf[512];int num = 0;int ret;int cmd = 0;char *arg[MAXARG];int arg_num;arg_num = argc - 1;int i = 0;for(i=0; i<arg_num; i++){arg[i] = argv[i+1];}if(argc < 2){fprintf(2, "xarg: xarg [process] [args...]\n");exit(1);}int j = 0;while(1){ret = read(0, buf+j, 1);if(ret != 1){break;}else if(buf[j] == '\n'){// printf("read number is : %d\n%s\n", num, buf);j = 0;num = 0;cmd = getcmd(buf, arg, arg_num);// printf("\n\n%d %d\n", cmd, arg_num);// printf("%s\n%s\n%s\n%s\n", arg[0], arg[1], arg[2], arg[3]);if(cmd == arg_num){printf("%d %d\n", cmd, arg_num);printf("no content of stdin\n");}else{if(fork() == 0){exec(argv[1], arg);fprintf(2, "exec failed\n");exit(1);}else{wait((int *)0);}}}else{j++;num++;}}for(i=0; i<cmd; i++){free(arg[i]);}exit(0);
}

(4)结果如下:
在这里插入图片描述
(5)总结:
在实现字符串的单词分割的时候,对于指针的操作出现问题。
char **arg的arg[]元素应该动态分配空间,而不是讲temp数组的指针头直接赋值。


总结

课程每年可能有变化,本文按照最新的2023计划表进行学习

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

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

相关文章

UE5-AI

AI角色 角色控制器 AI角色必须要一个角色控制器 角色控制器最基本只需要执行行为树&#xff0c;在EventOnPossess后runBehaviorTree 如果要的是一个角色&#xff0c;可以创建一个Character&#xff0c;在类默认设置中可以找到 Pawn->AIControllerClass&#xff0c;在这里…

WebGL开发地理信息系统

WebGL开发地理信息系统&#xff08;GIS&#xff09;是一项复杂且具有挑战性的任务&#xff0c;需要解决一系列技术难点。以下是一些主要的技术难点及其可能的解决方案。北京木奇移动技术有限公司&#xff0c;专业的软件外包开发公司&#xff0c;欢迎交流合作。 1.大规模数据渲染…

PHP序列化、反序列化

目录 一、PHP序列化&#xff1a;serialize() 1.对象序列化 2.pop链序列化 3.数组序列化 二、反序列化&#xff1a;unserialize() 三、魔术方法 ​四、NSSCTF相关简单题目 1.[SWPUCTF 2021 新生赛]ez_unserialize 2.[SWPUCTF 2021 新生赛]no_wakeup 学习参考&#xff1…

数据提取:构建企业智能决策的基石

在数字化时代&#xff0c;数据已成为企业最宝贵的资产之一。而数据提取&#xff0c;作为数据分析和智能决策的第一步&#xff0c;正日益成为企业构建竞争优势的关键环节。本文将探讨数据提取的重要性、方法以及它如何为企业的智能决策奠定坚实基础。 一、数据提取的重要性 洞…

全新市场阶段,Partisia BlockChain 将向 RWA、DeFi 等领域布局

Partisia Blockchain 是一个全新范式的 Layer1&#xff0c;该链通过 MPC 方案来构建链上隐私方案&#xff0c;同时该链通过系列独特且创新的设计&#xff0c;旨在进一步解决目前 Web3 中所面临的不可能三角问题&#xff0c;包括安全性、互操作性和可扩展性&#xff0c;为更多的…

MySQL深分页,limit 100000,10 优化

文章目录 一、limit深分页为什么会变慢二、优化方案2.1 通过子查询优化&#xff08;覆盖索引&#xff09;回顾B树结构覆盖索引把条件转移到主键索引树 2.2 INNER JOIN 延迟关联2.3 标签记录法&#xff08;要求id是有序的&#xff09;2.4 使用between...and... 我们日常做分页需…

拿捏红黑树(C++)

文章目录 前言一、红黑树介绍二、插入操作三、验证红黑树四、红黑树与AVL性能比较与应用五、总体代码总结 前言 我们之前介绍了一种AVL的高阶数据结构&#xff0c;在本篇文章中&#xff0c;我们将会介绍一种与AVL旗鼓相当的数据结构–红黑树。 我们并且会对它的部分接口进行模…

Autoxjs 实践-Spring Boot 集成 WebSocket

概述 最近弄了福袋工具&#xff0c;由于工具运行中&#xff0c;不好查看福袋结果&#xff0c;所以我想将福袋工具运行数据返回到后台&#xff0c;做数据统计、之后工具会越来越多&#xff0c;就弄了个后台&#xff0c;方便管理。 实现效果 WebSocket&#xff1f; websocket是…

动态规划(01背包+并查集)

P1455 搭配购买 题意&#xff1a;就是说有n朵云&#xff0c;每朵云有自己的价钱&#xff08;重量&#xff09;和价值&#xff08;价值&#xff09;&#xff0c;还有我自己现在有钱的数目&#xff08;背包&#xff09;&#xff0c;然后还告诉你&#xff0c;哪几朵云是属于捆绑销…

“独特团购策略引领小程序商城一月狂赚600万“

你是否曾经对那些富有创意且成功的商业模式心生羡慕&#xff0c;最终它们通过非凡的业绩证明了自身的价值&#xff1f;今日&#xff0c;我要分享的是一个独特的小程序商城案例&#xff0c;它凭借一种别出心裁的团购策略&#xff0c;在短短一个月内实现了超过600万的营收&#x…

LeetCode 56 合并区间

本题中可以学到的比较重要的方法 lambda表达式定义自定义比较器Comparator Arrays.sort(intervals,(v0,v1)->{return v0[0] - v1[0];}); (附 : 这种形式也适合于优先队列创建时的自定义比较器定义) 比如&#xff1a; PriorityQueue<Integer> minTop new Priorit…

JAVA小案例-输出100-150中能被3整除的数,每5个换行

JAVA小案例-输出100-150中能被3整除的数&#xff0c;每5个换行 代码如下&#xff1a; public class Continue {/*** continue练习&#xff0c;输出100-150中能被3整除的数&#xff0c;每5个换行* param args*/public static void main(String[] args) {int count 0;//计数器…

【kubernetes】探索k8s集群的存储卷、pvc和pv

目录 一、emptyDir存储卷 1.1 特点 1.2 用途 1.3部署 二、hostPath存储卷 2.1部署 2.1.1在 node01 节点上创建挂载目录 2.1.2在 node02 节点上创建挂载目录 2.1.3创建 Pod 资源 2.1.4访问测试 2.2 特点 2.3 用途 三、nfs共享存储卷 3.1特点 3.2用途 3.3部署 …

ARM32开发--GPIO输入模式

知不足而奋进 望远山而前行 目录 文章目录 前言 浮空输入 上拉输入 下拉输入 模拟输入 总结 前言 在数字电路设计和嵌入式系统开发中&#xff0c;理解输入信号的处理方式对确保系统稳定性和可靠性至关重要。不同的输入处理方式包括上拉输入、下拉输入、浮空输入和模拟输…

解决JSON.stringify 方法在序列化 BigInt 类型时的错误

今天学nest时&#xff0c;使用apifox发送请求获取数据&#xff0c;结果还一直报错&#xff0c;而且还是我从未见过的 Do not know how to serialize a BigInt at JSON.stringify (<anonymous>) at stringify&#xff0c; 我都是跟着人家敲的&#xff0c;我就纳闷了&…

06Docker-Compose和微服务部署

Docker-Compose 概述 Docker Compose通过一个单独的docker-compose.yml模板文件来定义一组相关联的应用容器&#xff0c;帮助我们实现多个相互关联的Docker容器的快速部署 一般一个docker-compose.yml对应完整的项目,项目中的服务和中间件对应不同的容器 Compose文件实质就…

高德面试:为什么Map不能插入null?

在 Java 中&#xff0c;Map 是属于 java.util 包下的一个接口&#xff08;interface&#xff09;&#xff0c;所以说“为什么 Map 不能插入 null&#xff1f;”这个问题本身问的不严谨。Map 部分类关系图如下&#xff1a; 所以&#xff0c;这里面试官其实想问的是&#xff1a;为…

【Python系列】Python 方法变量参数详解

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

RetroMAE-文本embedding算法

1)输入文本经掩码操作后由编码器&#xff08;Encoder&#xff09;映射为隐空间中的语义向量&#xff1b;而后解码器&#xff08;Decoder&#xff09;借助语义向量将另一段独立掩码的输入文本还原为原始的输入文本 2)编码器的掩码率为15%-30%&#xff1b;解码器的掩码率为50%-70…

【工具】批量SKU生成器

一个用户加我&#xff0c;要我帮忙写一个生成SKU的工具&#xff0c;他希望可以自定义生成的选项&#xff0c;可以批量生成。我到网上找了好久也没有找到好用的&#xff0c;就花了一下午写了这个生成sku的功能 工具支持批量生成SKU&#xff0c;支持自定义配置项&#xff0c;支持…