xv6 6.S081 Lab1: util

  • 写在前面
  • 实验介绍
  • 开始!
    • sleep
    • pingpong
    • Primes
    • Find
    • Xargs

拖了这么久,终于稍微有时间填坑了。今天介绍xv6的第一个实验util。代码在这里。废话不多说,我们开始吧。

写在前面

参考我的上一篇博客OS实验xv6 6.S081 开坑,这里给出了一些有用的参考资料。

实验介绍

这是MIT Lab1的官方指导书Lab1 Utilities

Lab1要求我们实现几个Unix中常用的工具函数:

  • sleep
  • pingpong
  • primes
  • find
  • xargs

开始!

sleep


这个任务要求利用调用系统调用函数sleep完成sleep n。。。这也太简单了吧。。。
但是这里还需要强调一下,在Hints中说得很清楚了,我们调用的是syscall的sleep,这时xv6提供的,而不是Linux环境中的< sys >中的sleep。

在user文件夹下新建sleep.c,判断一下输入格式(纯粹为了加多代码量),调用一下sleep即可。注意导的包,user.h为xv6提供的系统函数,types.h为其提供的变量类型

#include "kernel/types.h"
#include "user/user.h"const int duration_pos = 1;
typedef enum {wrong_char, success_parse, toomany_char} cmd_parse;
cmd_parse parse_cmd(int argc, char** argv);int
main(int argc, char** argv){//printf("%d, %s, %s \n",argc, argv[0], argv[1]);if(argc == 1){printf("Please enter the parameters!");exit();}else{cmd_parse parse_result;parse_result = parse_cmd(argc, argv);if(parse_result == toomany_char){printf("Too many args! \n");exit();}else if(parse_result == wrong_char){printf("Cannot input alphabet, number only \n");exit();}else{int duration = atoi(argv[duration_pos]);//printf("Sleeping %f", duration / 10.0);sleep(duration);exit();}}
}cmd_parse
parse_cmd(int argc, char** argv){if(argc > 2){return toomany_char;}else {int i = 0;while (argv[duration_pos][i] != '\0'){/* code */if(!('0' <= argv[duration_pos][i] && argv[duration_pos][i] <= '9')){return wrong_char;}i++;}}return success_parse;
}

pingpong


本任务要求实现利用管道实现进程间的通信:父进程发送ping,子进程收到后发送pong,父进程收到后将其打印出来
Hints 1:利用pipe()函数创建管道,pipe()函数接收一个长度为2的数组,数组下标0为读端、1为写端;
Hints 2:利用fork()函数创建新的进程;
Hints 3:利用read、write函数读写管道;

绘制出下面这张图就很好理解这个任务了。

下面给出代码实现:

#include "kernel/types.h"
#include "user/user.h"int
main(int argc, char** argv ){int pid;int parent_fd[2];int child_fd[2];char buf[20];//为父子进程建立管道pipe(child_fd); pipe(parent_fd);// Child Progressif((pid = fork()) == 0){close(parent_fd[1]);read(parent_fd[0],buf, 4);printf("%d: received %s\n",getpid(), buf);close(child_fd[0]);write(child_fd[1], "pong", sizeof(buf));exit();}// Parent Progresselse{close(parent_fd[0]);write(parent_fd[1], "ping",4);close(child_fd[1]);read(child_fd[0], buf, sizeof(buf));printf("%d: received %s\n", getpid(), buf);exit();}}

Primes


本任务要求完成质数筛选器
具体是什么意思呢?
它要求用fork和pipe实现:输入为2 ~ 35,输出为2 ~ 35间的所有质数,例如:2、3、5、7等。

算法比较简单,例如,第一次我们将2 ~ 35给到一个进程,这个进程发现给到的第一个数为2,则输出2,然后将不能被2除尽的数(3、5、7、9……)发送给下一个进程,下一个进程发现给到的第一个数为3,则输出3,然后将不能被3除尽的数(5、7……)发送给下一个进程……以此类推。我们可以通过下图说明这个过程。

好了,递归创建管道貌似就可以做了。

#include "kernel/types.h"
#include "user.h"void generate_nums();
void send_primes(int pd[], int infos[], int infoslen);
void check_pd(int pd[], int len);
void process(int pd[]);int
main(int argc, char** argv){//声明管道int pd[2];  //pipe descriper//创建管道pipe(pd);//check_pd(pd, 2);int pid;//Child Processif((pid = fork()) == 0){process(pd);exit();}//Parent Processelse{int nums[34];generate_nums(nums);send_primes(pd, nums, 34);//sleep(10);exit();}}void process(int pd[]){int p;int n;int len;int pid;int pd_child[2];int infos[34];int infos_i = 0;pipe(pd_child);//check_pd(pd_child, 2);close(pd[1]);len = read(pd[0], &p, sizeof(p));printf("prime %d\n", p);  while(len != 0) {len = read(pd[0], &n, sizeof(n));if(n % p != 0){*(infos + infos_i) = n;infos_i++;}}close(pd[0]);if(infos_i == 0) {exit();}// Child Processif((pid = fork()) == 0){process(pd_child);}// Parent Processelse{send_primes(pd_child, infos, infos_i);  }
}void
generate_nums(int nums[34]){int i = 0;for(int count = 2; count <= 35; count++){nums[i] = count;i++;}}void
check_pd(int pd[], int len){printf("pd:\n");for(int i = 0; i < len; i++){printf("%d \n", pd[i]);}
}void
send_primes(int pd[], int infos[], int infoslen){int info;close(pd[0]);for(int i = 0; i < infoslen; i++){info = infos[i];write(pd[1],&info,sizeof(info));}
}

Find


目标:写一个find函数
find函数的作用是什么呢?
其基本用法为 find arg1 arg2, 即在目录arg1下找到arg2。怎么写呢?完全不知道,因为这和file system挂钩。但是,MIT给了我们一个Hint:Look at user/ls.c to see how to read directories。于是就照着ls来写吧。这里有一个红利Bonus,就是可以直接copy grep.c的正则匹配代码,这样就能更快地进行文件的查找。

#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
#include "kernel/fs.h"//Copy from Grep.c
char buf[1024];
int match(char*, char*);
int matchhere(char*, char*);
int matchstar(int, char*, char*);int
match(char *re, char *text)
{if(re[0] == '^')return matchhere(re+1, text);do{  // must look at empty stringif(matchhere(re, text))return 1;}while(*text++ != '\0');return 0;
}// matchhere: search for re at beginning of text
int matchhere(char *re, char *text)
{if(re[0] == '\0')return 1;if(re[1] == '*')return matchstar(re[0], re+2, text);if(re[0] == '$' && re[1] == '\0')return *text == '\0';if(*text!='\0' && (re[0]=='.' || re[0]==*text))return matchhere(re+1, text+1);return 0;
}// matchstar: search for c*re at beginning of text
int matchstar(int c, char *re, char *text)
{do{  // a * matches zero or more instancesif(matchhere(re, text))return 1;}while(*text!='\0' && (*text++==c || c=='.'));return 0;
}/*find.c
*/
char* fmtname(char *path);
void find(char *path, char *re);int
main(int argc, char** argv){if(argc < 2){printf("Parameters are not enough\n");}else{//在路径path下递归搜索文件 find(argv[1], argv[2]);}exit();
}// 对ls中的fmtname,去掉了空白字符串
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++;// printf("len of p: %d\n", strlen(p));if(strlen(p) >= DIRSIZ)return p;memset(buf, 0, sizeof(buf));memmove(buf, p, strlen(p));//memset(buf+strlen(p), ' ', DIRSIZ-strlen(p));return buf;
}void
find(char *path, char *re){// printf("---------------------------------------------\n");// printf("path:%s\n", path);// printf("fmtpath:%s\n",fmtname(path));// printf("re:%s\n", re);char buf[512], *p;int fd;struct dirent de;struct stat st;if((fd = open(path, 0)) < 0){fprintf(2, "find: cannot open %s\n", path);return;}if(fstat(fd, &st) < 0){fprintf(2, "find: cannot stat %s\n", path);close(fd);return;}switch(st.type){case T_FILE://printf("File re: %s, fmtpath: %s\n", re, fmtname(path));if(match(re, fmtname(path)))printf("%s\n", path);break;//printf("%s %d %d %l\n", fmtname(path), st.type, st.ino, st.size);case T_DIR:if(strlen(path) + 1 + DIRSIZ + 1 > sizeof buf){printf("find: 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("find: cannot stat %s\n", buf);continue;}// printf("%s, %d\n",fmtname(buf), strlen(fmtname(buf)));// printf("%s\n",buf);// // printf("%d\n",strcmp(".", fmtname(buf)));// // printf("%d\n",strcmp("..", fmtname(buf)));char* lstname = fmtname(buf);// printf("lstname: %s\n", lstname);if(strcmp(".", lstname) == 0 || strcmp("..", lstname) == 0){//printf("%s %d %d %d\n", buf, st.type, st.ino, st.size);continue;}else{//printf("deep: %s %d %d %d\n", buf, st.type, st.ino, st.size);find(buf, re);}//printf("%s %d %d %d\n", fmtname(buf), st.type, st.ino, st.size);}break;}close(fd);
}

Xargs


简而言之,多参数实现吧,当用户输入ctrl+d时停止参数的输入。
这里要说明的是:对于输入的命令,我们要用exec执行,其中exec接收两个参数,第一个参数为命令cmd,第二个参数为一个数组,该数组的格式必须为{cmd, “arg1”, “arg2”, …, 0}

代码实现并不难,关键在于要理解xargs的用法。另外,在c语言中,输入ctrl+d后,buf长度为0,可据此来完成对ctrl+d的判断。另外,根据MIT的Hint:kernel/param.h declares MAXARG, which may be useful if you need to declare an argv.,我们可以声明一个数组来保存用户输入的每一个参数。好了,可以写代码了。

#include "kernel/types.h"
#include "kernel/stat.h"
#include "user.h"
#include "kernel/fs.h"
#include "kernel/param.h"#define CMDSTYLE        2char *cutoffinput(char *buf);
void substring(char s[], char sub[], int pos, int len);
void printargs(char* args[MAXARG][CMDSTYLE], int args_num);/* 打印参数 */
void
printargs(char* args[MAXARG][CMDSTYLE], int args_num){for (int i = 0; i < args_num; i++){/* code */printf("--------------args %d:--------------\n", i + 1);printf("cmd: %s, arg: %s, argslen: %d \n", args[i][0], args[i][1], strlen(args[i][1]));}}
/* 子串 */
void
substring(char s[], char *sub, int pos, int len) {int c = 0;   while (c < len) {*(sub + c) = s[pos+c];c++;}*(sub + c) = '\0';
}/* 截断 '\n' */
char*
cutoffinput(char *buf){/* 记得要为char *新分配一片地址空间,否则编译器默认指向同一片地址 */if(strlen(buf) > 1 && buf[strlen(buf) - 1] == '\n'){char *subbuff = (char*)malloc(sizeof(char) * (strlen(buf) - 1));substring(buf, subbuff, 0, strlen(buf) - 1);return subbuff;}else{char *subbuff = (char*)malloc(sizeof(char) * strlen(buf));strcpy(subbuff, buf);return subbuff;}
}int
main(int argc, char *argv[])
{/* code */int pid;char buf[MAXPATH];char *args[MAXARG];char *cmd;/* 默认命令为echo */if(argc == 1){cmd = "echo";}else{cmd = argv[1];}/* 计数器 */int args_num = 0;while (1){memset(buf, 0, sizeof(buf));gets(buf, MAXPATH);/* printf("buf:%s",buf); */char *arg = cutoffinput(buf);/* printf("xargs:gets arg: %s, arglen: %d\n", arg, strlen(arg)); *//* press ctrl + D */if(strlen(arg) == 0 || args_num >= MAXARG){break;}args[args_num]= arg;args_num++;}/* printargs(args, args_num);printf("Break Here\n");*//* 填充exec需要执行的命令至argv2exec */int argstartpos = 1;char *argv2exec[MAXARG];argv2exec[0] = cmd;for (; argstartpos < argc; argstartpos++){argv2exec[argstartpos] = argv[argstartpos - 2];}for (int i = 0; i < args_num; i++){/* code */argv2exec[i + argstartpos] = args[i];}argv2exec[args_num + argstartpos] = 0;/* 运行cmd */if((pid = fork()) == 0){   exec(cmd, argv2exec);    }  else{/* code */wait();}exit();
}

xv6 6.S081 Lab1: util相关推荐

  1. xv6 6.S081 Lab3: alloc

    xv6 6.S081 Lab3: alloc 写在前面 实验介绍 开始! 任务再描述 任务一实现 任务二实现 Buddy Allocator Code Thru 任务二的实现 alloc代码在这里.另 ...

  2. xv6 6.S081 Lab5: cow

    xv6 6.S081 Lab5: cow 写在前面 实验介绍 开始! cow代码在这里.完成了lazy后,cow的实现就非常明了了-- 写在前面 经典写在前面

  3. xv6 6.S081 Lab8: fs

    xv6 6.S081 Lab8: fs 写在前面 实验介绍 开始! Large File Symbolic links fs代码在这里.我的妈呀,终于要写完了,xv6的file system考察难度并 ...

  4. xv6 6.S081 Lab4: lazy

    xv6 6.S081 Lab4: lazy 写在前面 实验介绍 开始! 打印页表 实现Lazy Allocation 修改sbrk() 实现Lazy Allocation 完善Lazy Allocat ...

  5. xv6 6.S081 Lab7: Lock

    xv6 6.S081 Lab7: Lock 写在前面 实验介绍 开始! Memory Allocator Buffer Cache lock代码在这里.本次实验理解起来简单,做起来也容易 写在前面 老 ...

  6. XV6实验(2020)

    XV6实验记录(2020) 环境搭建 参考连接 Lab guidance (mit.edu) 6.S081 / Fall 2020 (mit.edu) xv6 book中文版 Lab1:Xv6 and ...

  7. Java 获取IP地址的工具类

    package cn.tolin.springboot.lab1.util;import javax.servlet.http.HttpServletRequest; import java.net. ...

  8. 操作系统MIT6.S081:[xv6参考手册第4章]->Trap与系统调用

    本系列文章为MIT6.S081的学习笔记,包含了参考手册.课程.实验三部分的内容,前面的系列文章链接如下 操作系统MIT6.S081:[xv6参考手册第1章]->操作系统接口 操作系统MIT6. ...

  9. 6.S081 Xv6 Lab 5: lazy page allocation

    Lab: xv6 lazy page allocation https://pdos.csail.mit.edu/6.S081/2020/labs/lazy.html 新的 2020 版哦. $ gi ...

最新文章

  1. linux开终端失败,Linux:终端提示符 (prompt) 不如期生效原因
  2. 理解jmeter聚合报告
  3. 最小二乘法,python3实现
  4. JZOJ 3870. 【NOIP2014八校联考第4场第1试10.19】单词检索(search)
  5. ZOJ - 2676 Network Wars(01分数规划+最小割)
  6. 跟随器反馈回路电阻_如何将短反馈回路设置为单独编码器
  7. java list 去除 重复值
  8. The mbstring extendsion is missing,Please check you PHP configuration
  9. 鸿蒙系统 第4节 Hi3861 WiFi操作,热点连接
  10. 一文了解地理数据和三维地理信息系统
  11. 面试前你要准备这些东西
  12. 利用爬虫数据做的研究_利用研究周增强数据科学能力
  13. 在Windows 10下配置 DirectX11 + Visual Studio 2017开发环境
  14. 堆栈c语言 矩形填色,堆栈涂色官方版下载|堆栈涂色安卓版v0.1下载 - 一游网手机游戏...
  15. python开发注册机_用python 写 Atlantis Word Processor 注册机
  16. 哔哩哔哩2021校招末班车来了!
  17. su oracle 登录不了,Oracle中su切换进去sqlplus登录失败的问题处理
  18. 提问的智慧 (全文)
  19. mac办公软件里值得推荐给大家的好软件
  20. 已声明“##”,但从未读取其值,解决办法

热门文章

  1. sql查询语句分支语句
  2. 64位 Fedora 11 硬盘安装 配置全解
  3. eclipse 是用来写客户端的,MyEclipse 是用来写服务器端的,谐音记忆法,My 买,买服务器这样就好记了。
  4. Cadence之ORCAD:导出Bom清单
  5. 苹果零日漏洞利用市售800万欧元
  6. springcloud config非对称加密
  7. Windows下vc开发chrome浏览器工程的一点粗浅理解和封装
  8. java ee框架技术进阶式教程_《JavaEE框架技术进阶式教程》新版任务式教案
  9. 李开复给中国学生的第二封信:从优秀到卓越
  10. java随机点名器_Java实现简单随机点名器