Xv6启动,lab 1

lab地址:https://pdos.csail.mit.edu/6.S081/2020/labs/util.html
课程地址:https://pdos.csail.mit.edu/6.S081/2020/schedule.html

启动xv6

git clone git://g.csail.mit.edu/xv6-labs-2020
cd xv6-labs-2020
git checkout util
make qemu

退出xv6

回到 monitor 界面:ctrl + a,然后按 c ,即可退出 xv6 的 shell 界面,进入 QEMU 的 monitor 界面,输入 q 按回车即可退出 QEMU。

终止 QEMU 进程:ctrl + a,然后按 x,即可终止 QEMU 进程,回到 Shell 界面。

sleep实验(easy)

在user文件夹下实现sleep.c
实现完成后,需要在Makefile的UPROGS下添加_sleep,下同。

#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"

int 
main(int argc, char **argv) 
{
  if (argc < 2) {
    printf("usage: sleep <ticks>\n");
  }
  sleep(atoi(argv[1]));
  exit(0);
}

pingpong实验(easy)

通过两个管道,实现子进程和父进程的交互。

#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"


int
main(int argc, char **argv)
{
    int pp[2], pc[2];
    pipe(pp); // parent => child
    pipe(pc); // child  => parent

    if(fork() == 0) {
        // child
        char buf;
        read(pp[0], &buf, 1);
        printf("%d: received ping\n", getpid());
        write(pc[1], &buf, 1);
    }
    else {
        // parent
        write(pp[1], "!", 1);
        char buf;
        read(pc[0], &buf, 1);
        printf("%d: received pong\n", getpid());
        wait(0);
    }

    exit(0);
}

primes实验(hard)

多进程实现质数筛的方法:

p = get a number from left neighbor
print p
loop:
    n = get a number from left neighbor
    if (p does not divide n)
        send n to right neighbor

注意,每个子进程打开文件描述符的数量是有限的,为16个。而每次fork出的新进程会复制父进程的文件描述符。因此,进程在fork后要及时关闭一定的文件描述符。

另外,设置计算的数字超过200,好像程序就不能正常执行了。

#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"

/*
    通过管道实现质数筛
*/

void sieve(int left_pipe[2]){
    // read and print 
    int p;
    read(left_pipe[0], &p, sizeof(p));
    if(p == -1) {
        exit(-1);
    }
    printf("prime %d\n", p);

    int right_pipe[2];
    pipe(right_pipe);

    if(fork() == 0) {
        // child process
        close(left_pipe[0]);
        close(right_pipe[1]);
        sieve(right_pipe);
    }
    else {
        // parent process
        close(right_pipe[0]); // no need read from right.
        int buf;
        while(read(left_pipe[0], &buf, sizeof(buf)) && buf != -1) {
            if(buf % p == 0) continue;
            write(right_pipe[1], &buf, sizeof(buf));
        }
        buf = -1;
        write(right_pipe[1], &buf, sizeof(buf));
        wait(0);
    }
    exit(0);
}


int main(int argc,  char **argv) {
    
    int input_pipe[2];
    pipe(input_pipe);

    if(fork() == 0) {
        // child process
        close(input_pipe[1]);
        sieve(input_pipe);
    }
    else {
        // parent process
        close(input_pipe[0]); // no need read
        int i;
        for(i=2; i<=100; i++) {
            write(input_pipe[1], &i, sizeof(i));
        }
        i = -1;
        write(input_pipe[1], &i, sizeof(i));
        wait(0);
    }
    exit(0);
}

find实验(moderate)

find程序。在指定目录中寻找特定的文件。

#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
#include "kernel/fs.h"


void find(char *path, char *target) {
    char buf[512], *p;
    int fd;
    struct dirent de;
    struct stat st;

    char *cur_dir = "/.";
    char *parent_dir = "/..";
    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:
        if(strcmp(path + strlen(path) - strlen(target), target) == 0) {
            printf("%s\n", path);
        }
        break;
    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;
            }
            if(strcmp(buf + strlen(buf) - strlen(cur_dir), cur_dir) == 0)
                continue;
            if(strcmp(buf + strlen(buf) - strlen(parent_dir), parent_dir) == 0)
                continue;
            find(buf, target);
        }
    }

    close(fd);

}

int main(int argc, char *argv[]){
    if(argc < 3) {
        exit(0);
    }
    find(argv[1], argv[2]);
    exit(0);
}

xargs(moderate)

编写xargs工具,用于从标准输入中读入多行信息。然后依次传给xargs后的程序进行执行。

#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
#include "kernel/fs.h"


void run(char *program, char **args) {
    // fork 子程序
    // 执行每一行的xargs任务
    if(fork() == 0) {
        exec(program, args);
        exit(0);
    }
    return;
}


int main(int argc, char **argv) {
    char buf[2048]; // 读入时使用的内存池。保存标准输入的内容
    char *p = buf, *last_p = buf; // p 用于输入,last_p则为当前输入的开头
    char *argsbuf[128];
    char **args = argsbuf; // 用于每行程序的执行

    for(int i=1; i<argc; i++) {
        // 后续的 exec 执行应该会自动忽略第一个参数
        // 故从1开始取。
        *args = argv[i];
        args++;
    }

    char **pa = args;
    while(read(0, p, 1) != 0) {
        if(*p == ' ' || *p == '\n') {
            char cur = *p;      // 用于后续判断 
            *p = '\0';          // 将buf中的当前为置\0
            *(pa++) = last_p;   // 补充参数
            last_p = p + 1;
            if(cur == '\n') {   // 当前是换行字符时,执行命令
                run(argv[1], argsbuf);
                pa = args;
            }
        }
        p++;
    }
    // 若未遇到换行,补充执行
    if(pa != args){
        *p = '\0';
        *(pa++) = last_p;
        run(argv[1], argsbuf);
    }
    while(wait(0) != -1) {};
    exit(0);
}

posted @ 2024-01-03 13:38  ckxkexing  阅读(46)  评论(0编辑  收藏  举报