ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

MIT6.S081-Lab Utilities

2022-03-08 17:33:18  阅读:178  来源: 互联网

标签:MIT6 buf Utilities char int fd path include S081


开始日期:22.2.24

操作系统:Ubuntu20.0.4

Link:Lab Utilities

目录

Lab Utilities

环境配置

每次的环境配置都是一段折磨又快乐的时光,这个实验的环境配置主要参考搭建MIT6.S081的实验环境
没有很复杂,再参考一下官网对Ubuntu的描述即可。

实验内容

在实验之前

  • 可以参考实验内容翻译来阅读
  • 需要阅读参考书的Chapter 1
  • 该课程在学完CS:APP3e之后来,会比较流畅,许多前置知识已经了解了
  • 可能需要事先了解的UINX(系统)函数

lab Boot xv6 (easy)

  • 参照着启动xv6就可以了,实验环境搭建完之后没啥难度

  • 注意clone下来的xv6-labs-2021文件夹存放在用户文件夹当中,一般就在桌面的左上角

  • To quit qemu type: Ctrl-a x.

    • 关闭qemu的方式是:先同时按ctrl+a,然后按x

sleep (easy)

  • 功能:使shell睡眠

  • 对照hints来写即可,但可能一开始不熟悉这种方式,写起来有点迷惑是很正常的,慢慢搞,搞得下来的

  • 本题很简单,调用系统函数sleep()即可,但要注意:

    • 传入的指针数组*argv[]存储的是char类型,需要用 atoi()char转换为int
  • 参考代码:

    #include"kernel/types.h"
    #include"kernel/stat.h"
    #include"user/user.h"
    
    int main(int agrc, char* agrv[]){
    	/* argc is the number of command, argv[] store the context of parameters */
    	if(agrc == 1){
    		printf("Please enter parameter of int");
    	}
    	else {
    		int time = atoi(agrv[1]);
    		sleep(time);
    	}
    	exit(0);
    }
    

pingpong (easy)

  • 功能:父子程序通过管道传递信息

  • 这里开始涉及到pipe(管道)的知识了,笔者一开始也是比较迷糊,但实际上理解之后就容易了

    • 调用pipe()函数即可建立管道,但注意要提前定义一个存放两个int元素的数组
      用来存放fd(file descriptor, 文件描述符)

    • 这个管道是以半双工的方式进行交流的,以防止出意外,也就是说,在使用管道读之前,得关闭写端;在使用管道写之前,得关闭读端。

      The fact that read blocks until it is impossible for new data to arrive is one reason that it’s important for the child to close the write end of the pipe before executing wc above: if one of wc ’s file descriptors referred to the write end of the pipe, wc would never see end-of-file.
      BOOK-RISCV-REV2 Chapter 1

      • 这里建立了两个通道,一个是child的,一个是parent的

        • 对于child,读写之前需要关闭父管道的写端,子管道的读端
        • 对于parent,读写之前需要关闭父管道的读端,子管道的写端
      • 灵魂图示

  • 参考代码

    /* Half-duplex Communication */
    #include"kernel/types.h"
    #include"kernel/stat.h"
    #include"user/user.h"
    
    int main(int argc, char* argv[]){
    	
    	int child_pfd[2];
    	int parent_pfd[2];
    	char buf[4]; /* "ping"or"pong" have 4 char */
    	
    	pipe(child_pfd);
    	pipe(parent_pfd);
    	
    	/* child */
    	if(fork() == 0){
    		int child_pid = getpid();
    		
    		/* close write of parent and read of child */
    		close(parent_pfd[1]);
    		close(child_pfd[0]);
    		
    		/*2: received "ping" then child print */
    		read(parent_pfd[0], buf, sizeof(buf));
    		printf("%d: received %s\n", child_pid, buf);
    		
    		/*3: write 4 bytes to parent */
    		write(child_pfd[1], "pong", sizeof(buf));
    		
    		exit(0);
    	}
    	
    	/* parent */
    	else{
    		int parent_pid = getpid();
    		
    		/* close read of parent and write of child */
    		close(parent_pfd[0]);
    		close(child_pfd[1]);
    		
    		/*1: sent 4 bytes to child */
    		write(parent_pfd[1], "ping", sizeof(buf));
    		
    		/*4: received "pong" then parent print */
    		read(child_pfd[0], buf, sizeof(buf));
    		printf("%d: received %s\n", parent_pid, buf);
    		
    		wait(0);
    		exit(0);
    	}
    }
    

primes (moderate)/(hard)

  • 给一个2 ~ 35的数组,输出其中的所有素数(限制:必须使用通道)

  • 这道题使用迭代,难度比较大

    • 在子程序,孙程序,曾孙程序...中迭代,不断地filter(过滤),每次过滤的结果可能是素数,也可能不是,但到最后一次的结果一定是素数。
    • 每次的numbers(结果)会传递给子程序用来继续过滤,但每次我们只打印一个prime
    • 注意每次完成读操作之后,要关闭读端
  • 参考代码

    #include"kernel/types.h"
    #include"kernel/stat.h"
    #include"user/user.h"
    
    #define LIMIT 35
    #define INT_SIZE 4
    #define READ 0
    #define WRITE 1
    #define NUMBERLIMIT 34  /* real limit of number is (35 - 2 + 1) = 34 */
    #define UNPRIME 0       /* 0 is not prime */
    
    void print_and_filter_primes(int* fd);
    
    int main(){
    	int first_fd[2];
    	int numbers[NUMBERLIMIT];
    	
        /* build first_fd*/
    	pipe(first_fd);
    	
    	/* first child */
    	if (fork() == 0)
            print_and_filter_primes(first_fd);
    	
    	
    	/* first parent */
    	else{
            close(first_fd[READ]);
      		/* feed numbers */
        	for (int i = 2; i <= LIMIT; ++i)
           		numbers[i - 2] = i;	     
            write(first_fd[WRITE], &numbers, (NUMBERLIMIT) * INT_SIZE);
            close(first_fd[WRITE]);
    
            wait(0);
            exit(0);
    	}
    	return 0;
    }
    
    void print_and_filter_primes(int* fd){
        close(fd[WRITE]);
    
        int prime = UNPRIME;
        int numbers[LIMIT];
        int next_fd[2];
        int temp;
        int count = 0;
    
        read(fd[READ], (int *)&prime, INT_SIZE);
    
        if (prime == UNPRIME)
            exit(0);
            
        /* the first number => 2 => is_prime */
        /* each time only print a prime */
        printf("prime %d\n", prime);
    
        /* filter numbers as next input */
        /* the next numbers may prime or un_prime */
        /* but the last number is prime */
        while (read(fd[READ], &temp, INT_SIZE) > 0)
            if (temp % prime != 0) 
                numbers[count++] = temp;
      
        /* aviod fd overflow*/
        close(fd[READ]);
    	
        /* build next_fd*/
    	pipe(next_fd);	
    	
        /* next child */
    	if (fork() == 0){
            print_and_filter_primes(fd);
    	}
    
        /* next parent */
        else{
            close(next_fd[READ]);
            write(next_fd[WRITE], &numbers, count * INT_SIZE);
            close(next_fd[WRITE]);
    
            wait(0);
            exit(0);
        }
    }
    

find (moderate)

  • 功能:从根目录(.)中找出所有目标文件(name

  • 这道题的难度主要在于对ls.c的理解,要比较透彻才行

  • 修改的基本都在switch

    • 对于file,我们需要调用函数compare()后将结果路径打印出来

      • 之所以要额外写个函数,是因为要一次性满足递归(recursion)下降,以便最后时一次性递归上升(可以理解为:在stack中一次性全部pop,之后一次性全部push,而不是一下pop,一下push)
      • compare()还需要辅助函数get_path_lastname()找出最后的名字来对比,该函数的主要思路是从最后一个char开始找到第一个slash('/')
        • eg ./a/c/b 中,b是最后一个char,从左数第三个/是对于b的第一个slash('/')
    • 对于directory,我们需要递归find继续进入,同时解决两个问题

      • 第一,组装新的路径,主要用到了追加函数memmove()和指针p,注意:路径本身是字符串,c风格的字符串最后一个字符是'\0';标准库函数strlen(s)可以返回字符串参数s的长度,但长度不包括末尾的'\0'
      • 第二,防止死循环,不进入当前目录.和父目录..;节约时间,不进入空文件de.inum == 0
  • 参考代码

    #include "kernel/types.h"
    #include "kernel/stat.h"
    #include "user/user.h"
    #include "kernel/fs.h"
    
    void find(char *path, char *name);
    char* get_path_lastname(char *path);
    void compare(char *path_lastname, char *name);
    
    int main(int argc, char *argv[]) {
    /*  // Input Error! 
        if (argc < 3){
            printf("Input Error!");
            exit(0);
        }
     */
        find(argv[1], argv[2]);
        exit(0);    
    }
    
    void find(char *path, char *name) {
        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:
            	/* empty dir is file(T_FILE)  */
                /* must use recursion in order to push and pop*/
                compare(path, name);
                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 || strcmp(".", de.name) == 0 || strcmp("..", de.name) == 0)
                        continue;
                    
                    memmove(p, de.name, strlen(de.name)); 
                    p[strlen(de.name)] = '\0';
                    find(buf, name);
                }
                break;
        }
        close(fd);
    }
    
    char* get_path_lastname(char *path) {
        static char buf[DIRSIZ+1];
        char *p;
    
        /* order: from the last char to first slash('/') */
        for(p = path + strlen(path); p >= path && *p != '/'; p--)
            ;
        
        /* since p-- point to last slash('/') */
        /* p++ point to last char */
        p++;  
    
        // Return file name to cmp 
        if(strlen(p) >= DIRSIZ)
            return p;
        memmove(buf, p, sizeof(p));
        p[strlen(buf)] = '\0';
        return buf;
    }
    
    void compare(char *path, char *name){
        if(strcmp(get_path_lastname(path), name) == 0)
            printf("%s\n", path);
        return;
    }
    
    /* 
    $ make qemu
    ...
    init: starting sh
    $ echo > b      // build a dir called 'b' that 'b' is sub-dir of '.'
    $ mkdir a       // build a dir called 'a' that 'a' is sub-dir of '.'
    $ echo > a/b    // build a dir called 'b' that 'b' is sub-dir of 'a'
    $ find . b      // find file that name is 'b' from system dir('.') 
    ./a/b
    $
     */
    
    /* 
    hierarchy of dir 
    // Directory is a file containing a sequence of dirent structures.
    #define DIRSIZ 14
    
    struct dirent {
      ushort inum; // the numbers of dir containing
      char name[DIRSIZ];
    };
    */
    
    /* 
    status of dir or file or device
    #define T_DIR     1   // Directory
    #define T_FILE    2   // File
    #define T_DEVICE  3   // Device
    
    struct stat {
      int dev;     // File system's disk device
      uint ino;    // Inode number
      short type;  // Type of file
      short nlink; // Number of links to file
      uint64 size; // Size of file in bytes
    };
     */
    

xargs (moderate)

  • 功能:追加将要调用函数的参数,当遇到\n时就立刻执行

    • 参考链接:xargs()

    • eg1. xargs为将要调用的函数echo追加了参数hello too

      xargs echo bye
      hello too
      =>
      bye hello too
      
    • eg2. 先调用echo,它的输出结果hello too作为xargs的输入,成为将要调用的函数echo的追加参数

      echo hello too | xargs echo bye
      =>
      bye hello too
      
  • all_args_buffer存储了所有参数

  • 我们传递给exec运行的是指针数组的地址args_parray,里面存储了将要执行的参数

  • 当遇到\n执行完之后,要回归原来的位置

    • eg. 当遇到\n执行完之后,要回归原来的位置(echo

      echo "1\n2" | xargs -n 1 echo line
      =>
      line 1
      line 2
      
  • 参考代码

    #include"kernel/types.h"
    #include"kernel/stat.h"
    #include"user/user.h"
    #include "kernel/fs.h"
    #include "kernel/param.h"
    
    int main(int argc, char **argv) {
        int i, j;
        char *args_parray[MAXARG];
        char all_args_buffer[256];
        char *ptr_buffer = all_args_buffer;
        char *ptr_array =  ptr_buffer;
    
        for(i = 1, j = 0; i < argc; i++)
            args_parray[j++] = argv[i]; /* when loop break, j == argv - 1 */
    
        int length;
        int total_length = 0;
        while (read(0, ptr_buffer, MAXARG) > 0){ /* 0 is pipe of reading */
            total_length += length;
            if(total_length > 256){
                printf("the args is too long!");
                exit(0);
            }
    
            for(i = 0; i < length; ++i){
                if(ptr_buffer[i] == ' '){
                    ptr_buffer[i] = '\0'; /* c-style: the last of string has '\0' */
                    args_parray[j++] = ptr_array; /* add new args to args_parray */
                    ptr_array = &ptr_buffer[i + 1]; /* ptr_array point to next */
                }
                else if(ptr_buffer[i] == '\n'){
                    ptr_buffer[i] = '\0';
                    args_parray[j++] = ptr_array;
                    args_parray[j] = '\0'; /* as args of exec (c-style: string has '\0') */
                    ptr_array = &ptr_buffer[i + 1];
                    
                    if(fork() == 0){
                        exec(argv[1], args_parray);
                        exit(0);
                    }
    
                    j = argc - 1; /* comeback, eg: echo "1\n2" | xargs -n 1 echo line */
                    wait(0);
                }
            }
            ptr_buffer + length;
        }
        exit(0);
    }
    
  • 根据提示,我们还需要修改find(),以解决从.sh文件中读出的每条命令都加上$的问题。我们希望只有一个$,笔者目前没有解决这个bug

总结

  • 完成日期22.3.8

  • 刚开学期间有许多杂事,返校需要自费核酸之类的,还有免修。劳累之后就得好好休息,就落下了

  • 难度目前没有很大

  • 最近在听《想和你漫步在午后》夏小调,《可风》黄建为

  • 自测试图(笔者未解决关于time.txtbug

标签:MIT6,buf,Utilities,char,int,fd,path,include,S081
来源: https://www.cnblogs.com/duile/p/15981486.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有