网站建设列入什么会计科目,推广软件赚钱的app,装修网站怎样做,wordpress界面主题系列文章目录
操作系统入门系列-MIT6.S081#xff08;操作系统#xff09;学习笔记#xff08;一#xff09;---- 操作系统介绍与接口示例 操作系统入门系列-MIT6.828#xff08;操作系统工程#xff09;学习笔记#xff08;二#xff09;----课程实验环境搭建#x…系列文章目录
操作系统入门系列-MIT6.S081操作系统学习笔记一---- 操作系统介绍与接口示例 操作系统入门系列-MIT6.828操作系统工程学习笔记二----课程实验环境搭建wsl2ubuntuquemxv6 操作系统入门系列-MIT6.828操作系统工程学习笔记三---- xv6初探与实验一(Lab: Xv6 and Unix utilities) 文章目录 系列文章目录前言一、xv6文档第一章1. 引论 二、实验一1.启动xv62.实现休眠函数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 的内部设计包括 BSDLinuxMac OS XSolaris 甚至 Microsoft Windows 在某种程度上都有类似 Unix 的接口理解 xv6 是理解这些操作系统的一个良好起点。 首先需要对操作系统有一个系统结构的大致概念如下图 如图所示操作系统的核心就是kernel。kernel起到了桥梁的作用连接各种应用程序和底层硬件资源。从软件编程者的角度来看程序员就是使用各种kernel提供的系统调用函数来实现各种各样的功能。xv6的系统调用函数如下图所示 后面的实验就是需要调用这些系统调用函数来实现相应的功能比如在Linux里面常用的find、xargs等命令的简易版。 在之前的文章中已经将第一章的部分进行了讲解详情见 操作系统入门系列-MIT6.S081操作系统学习笔记一---- 操作系统介绍与接口示例
二、实验一
1.启动xv6
详见xv6环境的配置和启动 操作系统入门系列-MIT6.828操作系统工程学习笔记二----课程实验环境搭建wsl2ubuntuquemxv6 1实验系统目录 整个实验代码的文件目录如下我们需要关注
1.绿色的”grade-lab-util“可执行文件它是测试机用来测试你的实验代码正确性。
2.kernel文件夹是xv6的kernel代码
3.Makefile是用来编译内核的需要在这里添加参数我们写的实验代码才能编译进去
4.user文件夹是我们添加自己实验代码的地方也就是用户空间 2Makefile添加文件 3退出xv6 使用”ctrla“后按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.hint 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.hint 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.hvoid 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(i0;i35;i){ret read(p[0], numi, 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(i1;inumber;i){if((num[i]%prime)!0){write(p1[1], numi, 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(i3;i35;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.hchar* fmtname(char *path)
{char *p;// Find first character after last slash.for(ppathstrlen(path); p path *p ! /; p--);p;return p;
}int find(char *name, char *p)
{int fd;int path0;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 bufstrlen(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.hint getcmd(char *buf, char**arg, int arg_num)
{int i;int j;j 0;arg[arg_num] (char *)malloc(30 * sizeof(char));for(i0; i512; 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(i0; iarg_num; i){arg[i] argv[i1];}if(argc 2){fprintf(2, xarg: xarg [process] [args...]\n);exit(1);}int j 0;while(1){ret read(0, bufj, 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(i0; icmd; i){free(arg[i]);}exit(0);
}4结果如下 5总结 在实现字符串的单词分割的时候对于指针的操作出现问题。 char **arg的arg[]元素应该动态分配空间而不是讲temp数组的指针头直接赋值。 总结
课程每年可能有变化本文按照最新的2023计划表进行学习