xv6 6.S081 Lab1: util
拖了這麼久,終於稍微有時間填坑了。今天介紹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 Progress
if((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 Progress
else{
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 Process
if((pid = fork()) == 0){
process(pd);
exit();
}
//Parent Process
else{
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 Process
if((pid = fork()) == 0){
process(pd_child);
}
// Parent Process
else{
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 string
if(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 instances
if(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 2
char *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][CMDSTYLE];
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][0] = cmd;
args[args_num][1] = arg;
args_num++;
}
/*
printargs(args, args_num);
printf("Break Here\n");
*/
/* 填充exec需要執行的命令至argv2exec */
int argstartpos = 1;
char *argv2exec[MAXARG];
argv2exec[0] = cmd;
if(argc == 3)
{
/* 從2開始 */
argstartpos++;
argv2exec[1] = argv[2];
}
else if (argc >= 3)
{
printf("xargs: too many initial args, only 2 permitted! \n");
exit();
}
for (int i = 0; i < args_num; i++)
{
/* code */
argv2exec[i + argstartpos] = args[i][1];
}
argv2exec[args_num + argstartpos] = 0;
/* 執行cmd */
if((pid = fork()) == 0){
exec(cmd, argv2exec);
}
else
{
/* code */
wait();
}
exit();
}
相關文章
- MIT xv6 2020系列實驗:Lab1 UtilitiesMIT
- MIT 6.S081 xv6除錯不完全指北MIT除錯
- MIT6.S081 - Lab1: Xv6 and Unix utilitiesMIT
- MIT 6.S081 聊聊xv6中的檔案系統(上)MIT
- MIT 6.S081 聊聊xv6的檔案系統(中)日誌層與事務MIT
- csapp Lab1APP
- UTIL
- Lab1 記錄
- MIT 6.S081 Lab File SystemMIT
- xv6 lab9
- xv6 lab10: mmap
- xv6:labs2 syscall
- mit6.828 - lab1筆記MIT筆記
- CSAPP DATA LAB1————位運算APP
- CSAPP:Lab1 -DataLab 超詳解APP
- xv6(riscv)上實現kprobe
- java.util.ConcurrentModificationExceptionJavaException
- jdbc Util 工具類JDBC
- java.util.PropertiesJava
- LAB1 啟動作業系統作業系統
- java.util.Date類Java
- java.util.concurrent.RejectedExecutionExceptionJavaException
- java util.Date 轉 LocalDateTimeJavaLDA
- Flutter Flame教程11 -- Util 工具Flutter
- MIT 6.824(Spring 2020) Lab1: MapReduce 文件翻譯MITSpring
- cs144 lab0 lab1記錄CS144
- xv6學習筆記(4) : 程式排程筆記
- 分析 java.util.Hashtable 原始碼Java原始碼
- util.promisify 的那些事兒
- java原始碼-java.util.ListJava原始碼
- 好用的java.util.Objects類JavaObject
- MIT xv6 2020系列實驗:Lab8 lockMIT
- XV6學習筆記(2) :記憶體管理筆記記憶體
- CS144 計算機網路 Lab1:Stream ReassemblerCS144計算機網路
- java.util.regex.Matcher 類的方法Java
- java.util.Arrays 快速使用介紹Java
- Util 應用框架 UI 全新升級框架UI
- Node.js util 模組解讀Node.js