当前位置: 首页 > news >正文

(undone) MIT6.S081 2023 一个月速通 (Day2: LAB1 Utilities)

实验网页:https://pdos.csail.mit.edu/6.S081/2023/labs/util.html


从网页描述中可以得到一些有用的信息:
1.可以执行 make grade 来测试自己的代码,获取得分。但这个命令会同时运行所有测试。
2.如果要单独对某个作业进行测试,有两种命令 (在 host 上执行,不是在 xv6 里执行)

./grade-lab-util sleep
make GRADEFLAGS=sleep grade

这次 LAB 一共有五个实验,如下:

  • sleep 简单
  • pingpong 简单
  • prime 困难
  • find 中等
  • xargs 中等

我们开始吧


任务1:完成 sleep 作业 (完成)

根据 LAB 网页要求,添加一个 sleep 命令,实现 sleep 10 能暂停 10 秒即可
在这里插入图片描述

这部分涉及到的源码其实很多,比如:
1.sleep 如何被编译进 fs.img
2.timer是怎么计数的
3.内核怎么切换进用户态,把 sleep 加载从磁盘加载进内存等等

但如果要把这些代码都看懂再开始做,那就太久了,这也不是我们平时做科研和工程的方式。

坚持使用最小的代价完成任务,等所有 LABS 做完,再去查漏补缺,或许这才是做 xv6 实验的正确方式。

但我们最好尽量不看讲义,毕竟现实的科研和工程没有讲义,只有一个 TARGET

现在的目标很明确,就是添加一个 sleep 命令。

首先,我们有和 sleep 命令相同的命令,比如 ls 命令,执行效果如下:
在这里插入图片描述

由于 sleep 命令和 ls 命令都是用户程序,那么参考 ls 命令的实现方式一定对我们实现 sleep 命令大有帮助,我们先看 ls.c 文件

可以在 user/ls.c 看到 ls 命令实现细节,如下:

#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
#include "kernel/fs.h"
#include "kernel/fcntl.h"char*
fmtname(char *path)
{static char buf[DIRSIZ+1];char *p;// Find first character after last slash.for(p=path+strlen(path); p >= path && *p != '/'; p--);p++;// Return blank-padded name.if(strlen(p) >= DIRSIZ)return p;memmove(buf, p, strlen(p));memset(buf+strlen(p), ' ', DIRSIZ-strlen(p));return buf;
}void
ls(char *path)
{char buf[512], *p;int fd;struct dirent de;struct stat st;if((fd = open(path, O_RDONLY)) < 0){fprintf(2, "ls: cannot open %s\n", path);return;}if(fstat(fd, &st) < 0){fprintf(2, "ls: cannot stat %s\n", path);close(fd);return;}switch(st.type){case T_DEVICE:case T_FILE:printf("%s %d %d %l\n", fmtname(path), st.type, st.ino, st.size);break;case T_DIR:if(strlen(path) + 1 + DIRSIZ + 1 > sizeof buf){printf("ls: path too long\n");break;}strcpy(buf, path);p = buf+strlen(buf);*p++ = '/';while(read(fd, &de, sizeof(de)) == sizeof(de)){if(de.inum == 0)continue;memmove(p, de.name, DIRSIZ);p[DIRSIZ] = 0;if(stat(buf, &st) < 0){printf("ls: cannot stat %s\n", buf);continue;}printf("%s %d %d %d\n", fmtname(buf), st.type, st.ino, st.size);}break;}close(fd);
}int
main(int argc, char *argv[])
{int i;if(argc < 2){ls(".");exit(0);}for(i=1; i<argc; i++)ls(argv[i]);exit(0);
}

可以看到 ls 命令的实现中使用了类似 openexitclose 这样的系统调用 API,如果我们代码跟踪进去,应该就能看到 xv6 目前所有支持的系统调用 API

open 跟踪进去,可以看到在 user/user.h 中定义的一堆 API

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);

可以看到,这是 xv6 提供给用户程序的系统调用,以及一些用户态库函数

在 23 行惊讶地发现,xv6 已经提供了 sleep() 系统调用 API,那我估计这事儿应该很容易完成

直接在 user/ 文件夹下添加一个 sleep.c 文件,代码如下:

#include "kernel/types.h" // user.h 自定义了数据类型
#include "user/user.h"int
main(int argc, char *argv[])
{if(argc != 2){fprintf(2, "usage: sleep [seconds]\n");exit(1);}sleep(atoi(argv[1]));exit(0);}

由于这是一个新的 C 文件,并没有在 Makefile 里添加依赖,那么很自然的想要在 Makefile 里做对应的修改。首先在 Makefile 里搜索 ls,在 Makefile : 174 找到对应的 UPROGS 用户程序列表,我们把 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\

运行 make qemu,运行 sleep 10 看看效果
在这里插入图片描述

sleep 10 确实停留了一小会儿,但不到两秒就结束了。观察 MIT6.S081 讲义,也没有说停留多久,只是说停留一小会儿

我们跑跑测试看看
在这里插入图片描述

测试通过,这个真是出乎意料的简单。

让我们提升一下难度,研究为什么这个 sleep 10 仅仅持续了不到2秒就结束 -------- start

这部分涉及的代码和知识点也有点多,反正 xv6 实验讲义也没要求,先 skip 吧。过完实验再回来思考

让我们提升一下难度,研究为什么这个 sleep 10 仅仅持续了不到2秒就结束 -------- end


任务2:完成 pingpong 作业(完成)

这个作业很简单,就是使用 fork, pipe, getpid, write, read 等系统调用实现一个 “两个进程通过导管来回传输字符” 的例子。

代码如下:

#include "kernel/types.h" // user.h 自定义了数据类型
#include "user/user.h"int main() {int ftoc[2]; // 管道1:父进程到子进程int ctof[2]; // 管道2:子进程到父进程// 0 是读端,1是写端// 创建管道if (pipe(ftoc) == -1 || pipe(ctof) == -1) {fprintf(2, "error: create pipe\n");exit(1);}int pid = fork();if (pid < 0) {fprintf(2, "error: fork\n");exit(1);}if (pid == 0) { // 子进程// 子进程 pidint child_pid = getpid();// 从父进程读取一个字节char receivemsg = '\0';read(ftoc[0], &receivemsg, 1);printf("%d: received ping\n", child_pid);printf("%d: received %c\n", child_pid, receivemsg);// 向父进程发送一个字节char sendmsg = 'B'; // 发送的字节write(ctof[1], &sendmsg, 1);close(ftoc[0]); // 关闭父到子管道的读端close(ftoc[1]); // 关闭父到子管道的写端close(ctof[0]); // 关闭子到父管道的读端close(ctof[1]); // 关闭子到父管道的写端exit(0);} else { // 父进程// 父进程 pidint father_pid = getpid();// 向子进程发送一个字节char sendmsg = 'A'; // 发送的字节write(ftoc[1], &sendmsg, 1);// 从子进程读取一个字节char receivemsg = '\0';read(ctof[0], &receivemsg, 1);printf("%d: received pong\n", father_pid);printf("%d: received %c\n", father_pid, receivemsg);close(ftoc[0]); // 关闭父到子管道的读端close(ftoc[1]); // 关闭父到子管道的写端close(ctof[0]); // 关闭子到父管道的读端close(ctof[1]); // 关闭子到父管道的写端exit(0);}exit(0);
}

分别是 user/pingpong.c,以及在 Makefile 相应位置加上 pingpong

先运行 make qemu 进行编译,随后执行测试,通过
在这里插入图片描述


任务3:完成 prime 作业

TODO: here


任务4:完成 find 作业

TODO: here


任务5:完成 xargs 作业

TODO: here



http://www.mrgr.cn/news/65100.html

相关文章:

  • (五)Spark大数据开发实战:灵活运用PySpark常用DataFrame API
  • 进度条的实现(配合make和makefile超详细)
  • 全志A133 android10 LVDS幅值调节
  • 【C++类和对象篇】类和对象的六大默认成员函数——构造,析构,拷贝构造,赋值重载,普通对象取地址重载,const对象取地址重载
  • SpringBoot+Shiro权限管理
  • three.js 智慧城市扫光效果
  • 音频模型介绍
  • LM Head weights;ChatGPT-3词汇量:175,000;llama7b 词汇量,词嵌入维度:4096
  • 苍穹外卖 查询订单明细
  • 删除 git submodule
  • 软件测试--BUG篇
  • SAR_ADC介绍和建模
  • 长期缺乏技术规划的后果与应对策略
  • 大型音频模型:AudioLLMs
  • 在美团外卖上抢券 Python来实现
  • 负载均衡算法
  • [vulnhub] DC: 8
  • 【098】基于SpringBoot+Vue实现的垃圾分类系统
  • 【笔试题】迈入offer的新大门
  • 统信UOS设备驱动开发-调试优化
  • 好多好多的排序方法——(C语言)
  • synchronized加锁原理以及锁升级过程
  • 2025上海市公务员考试报名流程详细教程
  • 数据结构之树
  • 简记Vue3(三)—— ref、props、生命周期、hooks
  • 如何基于pdf2image实现pdf批量转换为图片