zoukankan      html  css  js  c++  java
  • MIT-6.S081-2020实验(xv6-riscv64)一:util

    实验文档

    概述

    实验一主要涉及调用系统调用函数,这些系统调用函数基本都是符合POSIX规范的,和操作系统本身关系较小,在调试的时候也可以先把程序在外部的Linux下跑通然后再放进xv6中运行。

    内容

    sleep

    基本没什么特别的内容,按说明的做就行了。

    #include "kernel/types.h"
    #include "user/user.h"
    
    int main(int argc, char *argv[]) {
        int i;
        if (argc < 2) {
            printf("sleep: tick number is not specified
    ");
            exit(0);
        }
        i = atoi(argv[1]);
        if (i <= 0) {
            printf("sleep: tick number is invalid
    ");
            exit(0);
        }
        sleep(i);
        exit(0);
    }
    

    pingpong

    涉及进程创建和管道,当一个进程在read的时候会挂起直至读到内容,所以进程的执行顺序也是非常清晰的。

    #include "kernel/types.h"
    #include "user/user.h"
    
    int main() {
        int parent_fd[2], child_fd[2];
        char buf[16];
        pipe(parent_fd); pipe(child_fd);
        if (fork() == 0) {
            read(parent_fd[0], buf, 4);
            buf[4] = ''; printf("%d: received %s
    ", getpid(), buf);
            write(child_fd[1], "pong", 4);
        } else {
            write(parent_fd[1], "ping", 4);
            read(child_fd[0], buf, 4);
            buf[4] = ''; printf("%d: received %s
    ", getpid(), buf);
        }
        exit(0);
    }
    

    primes

    这个算是管道比较高级的应用,有点流水线那味道。根据实验文档所给的参考链接里的图片

    给人一种每个进程都是筛完合数然后将筛完的数一股脑传给下一级进程的感觉,其实不然,这样一方面需要多一个缓冲区来存储筛完的数,另一方面也不方便并行。实际上应该更好地利用管道的队列性质。对于每个进程,从输入管道得到第一个质数后就创建子进程,然后对输入管道剩下的数进行筛选,如果合法就放入输出管道,这样多个进程同时操作,也不用缓冲区了。子进程中创建子进程这种操作很难直接表示,需要用到递归思想。

    #include "kernel/types.h"
    #include "user/user.h"
    
    void f(int pp) {
        int prime;
        if (read(pp, (char *)&prime, 4) != 0) {
            printf("prime %d
    ", prime);
            int p[2]; pipe(p);
            if (fork() == 0) {
                close(p[1]); f(p[0]);
            } else {
                int t;
                while (read(pp, (char *)&t, 4) != 0) {
                    if (t % prime != 0) write(p[1], (char *)&t, 4);
                }
                close(p[1]); close(p[0]); close(pp); wait(0);
            }
        } else close(pp);
    }
    int main() {
        int i, p[2]; pipe(p);
        if (fork() == 0) {
            close(p[1]); f(p[0]);
        } else {
            for (i = 2; i < 36; i++) write(p[1], (char *)&i, 4);
            close(p[1]); close(p[0]); wait(0);
        }
        exit(0);
    }      
    

    注意每次fork以后会给当前的管道添加一个引用,而想要关闭一个管道必须将它的所有引用都关闭才行。因此每次在fork之后关闭不用的管道是一个好习惯,防止忘关导致其他进程读不到eof。

    find

    基本上套用ls.c里的内容。

    #include "kernel/types.h"
    #include "kernel/stat.h"
    #include "user/user.h"
    #include "kernel/fs.h"
    
    const char *now = ".", *par = "..";
    
    char* fmtname(char *path) {
        char *p;
        for(p = path + strlen(path); p >= path && *p != '/'; p--);
        p++;
        return p;
    }
    
    void find(char *path, char *pattern) {
        char buf[128], *p;
        int fd;
        struct dirent de;
        struct stat st;
    
        if((fd = open(path, 0)) < 0){
            printf("find: cannot open %s
    ", path);
            return;
        }
    
        if(fstat(fd, &st) < 0){
            printf("find: cannot stat %s
    ", path);
            close(fd);
            return;
        }
    
        switch(st.type){
            case T_FILE:
                if (strcmp(pattern, fmtname(path)) == 0) printf("%s
    ", path);
                break;
    
            case T_DIR:
                if(strlen(path) + 1 + DIRSIZ + 1 > sizeof buf){
                    printf("ls: path too long
    ");
                    break;
                }
                strcpy(buf, path);
                p = buf + strlen(buf);
                *p++ = '/';
                while(read(fd, &de, sizeof(de)) == sizeof(de)){
                    if(de.inum == 0) continue;
                    if (strcmp(de.name, now) == 0 || strcmp(de.name, par) == 0) continue;
                    memmove(p, de.name, DIRSIZ);
                    p[DIRSIZ] = 0;
                    find(buf, pattern);
                }
                break;
        }
        close(fd);
    }
    
    int main(int argc, char *argv[]) {
        if (argc < 3) {
            printf("find: argument is less than 2
    ");
            exit(0);
        }
        find(argv[1], argv[2]); exit(0);
    }
    

    xargs

    也没啥好说的,基本就是对命令行参数和标准输入的字符串处理。

    #include "kernel/types.h"
    #include "kernel/param.h"
    #include "user/user.h"
    
    int main(int argc, char *argv[]) {
        char line[256], *p[MAXARG], ch;
        int lines = 0, linen, ps = 0, pn, i, j;
        for (i = 0; i < argc - 1; i++) {
            p[ps++] = line + lines;
            for (j = 0; j < strlen(argv[i + 1]); j++)
                line[lines++] = argv[i + 1][j];
            line[lines++] = '';
        }
        linen = lines; pn = ps; p[pn++] = line + linen;
        while (read(0, &ch, 1) > 0) {
            if (ch == '
    ') {
                line[linen++] = ''; p[pn++] = 0;
                if (fork() == 0) exec(argv[1], p);
                else {
                    wait(0); linen = lines; pn = ps; p[pn++] = line + linen;
                }
            } else if (ch == ' ') {
                line[linen++] = ''; p[pn++] = line + linen;
            } else line[linen++] = ch;
        }
        exit(0);
    }
    
  • 相关阅读:
    相关术语随笔
    JDK简介和mac下安装和查看版本命令
    英语
    英语学习2
    英语学习-19.1
    为什么java是只有值传递而没有引用传递
    线程
    关于同步异步

    jdk动态代理实现原理总结
  • 原文地址:https://www.cnblogs.com/YuanZiming/p/14218987.html
Copyright © 2011-2022 走看看