首页 > 其他分享 >[MIT 6.S081] Lab: Xv6 and Unix utilities

[MIT 6.S081] Lab: Xv6 and Unix utilities

时间:2024-01-21 17:23:19浏览次数:24  
标签:char int utilities Lab Xv6 pipe close include buf

Lab: Xv6 and Unix utilities

Grade

sleep

sleep 格式如下

sleep 5

这边需要使用 kernal/stat.h 中的 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 digit");
        exit(1);
    }

    int is_digit = 1, sec = 0;
    for (const char* s = argv[1]; *s; s ++) {
        if (*s >= '0' && *s <= '9') {
            sec = sec * 10 + *s - '0';
        } else {
            is_digit = 0;
            break;
        }
    }

    if (!is_digit) {
        printf("argv must be int");
        exit(1);
    }

    sleep(sec);
    exit(0);
}

pingpong

pingpong 需要父进程和子进程之间具有交流信息的能力,也就是使用一对管道。对于父进程,先向子进程传输一个字节的信息,然后等待子进程返回一个字节的信息后 ,输出 pong 。对于子进程来说,需要先接收信息,然后输出 ping ,再将信息传输回去。要记住的是,及时关闭各个进程的通道读端和写端,也就是及时释放资源。

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

int main() {
    const char* msg = "a";
    char buf[2] = {};

    int pipe_p_to_c[2], pipe_c_to_p[2];
    
    // 0:= read fd
    // 1:= write fd
    pipe(pipe_p_to_c);
    pipe(pipe_c_to_p);

    // == 0 := ch p
    if (fork() == 0) {
        close(pipe_p_to_c[0]);
        close(pipe_c_to_p[1]);
        
        read(pipe_p_to_c[0], buf, 1);
        printf("%d: received ping\n", getpid());   
        write(pipe_c_to_p[1], msg, 1);
        
        close(pipe_p_to_c[1]);
        close(pipe_c_to_p[0]);
    } else {
        close(pipe_c_to_p[0]);
        close(pipe_p_to_c[1]);

        write(pipe_p_to_c[1], msg, 1);
        wait(0);
        read(pipe_c_to_p[0], buf, 1);
        printf("%d: received pong\n", getpid());
        
        close(pipe_c_to_p[1]);
        close(pipe_p_to_c[0]);
    }

    exit(0);
}

primes

这一步就比较困难。

首先 primes 的要求是:在每个进程中输出还未筛出的第一个素数,并在这个进程中进行一轮筛法,将剩下的数使用 pipe 传递给下一个进程。

std::vector<int> pri;
bool is_not_pri[N];

void GetPrime() {
    is_not_pro[0] = is_not_pri[1] = true;
    for (int i = 2; i < N; i ++) {
		if (is_not_pri[i])
            continue;
        pri.emplace_back(i);
        for (int j = i * 2; j < N; j += i) {
			is_not_pri[j] = true;
        }
    }
}

也就是说,每个进程相当于是 continue 之后的步骤。由于数字范围比较小,可以直接将目前得到的素数作为基准,用这个素数筛去其倍数即可。

需要注意的是,在这里特别要留意资源释放的问题。每次开启 pipe ,就必须要释放掉所可能不需要的 fd 。同时,父进程需要保留到所有子进程结束后才可退出,这时候就需要 wait() 了。

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

__attribute__((noreturn))
void dfs(int rd) {
    int n;
    if (read(rd, &n, 4) == 0) {
        exit(0);
    }
    printf("prime %d\n", n);
    
    int p[2];
    pipe(p);
    
    if (fork() == 0) {
        close(p[0]);
        int m;
        while (read(rd, &m, 4)) {
            if (m % n) {
                write(p[1], &m, 4);
            }
        }
        close(rd);
        close(p[1]);
    } else {
        close(p[1]);
        dfs(p[0]);
    }

    wait(0);
    exit(0);
}

int main() {
    int p[2];
    pipe(p);

    for (int i = 2; i <= 35; i ++) {
        write(p[1], &i, 4);
    }
    close(p[1]);
    dfs(p[0]);

    wait(0);
    exit(0);
}

find

这块可以直接参考 ls 的实现,观察 ls 是如何遍历目录的,find 只是多了需要比较名字的步骤。

#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
#include "kernel/fs.h"
#include <float.h>

char* get_filename(char* path) {
    static char buf[DIRSIZ + 1] = {};
    
    char* p;
    for (p = path + strlen(path); p >= path && *p != '/'; p --);
    p ++;

    if (strlen(p) >= DIRSIZ) {
        return p;
    }
    memmove(buf, p, strlen(p));
    memset(buf + strlen(p), ' ', DIRSIZ - strlen(p));

    return buf;
}

void find(char *path, char *tar) {
    char buf[512];
    int fd;
    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_DEVICE:
        case T_FILE:
            if (strcmp(tar, get_filename(path)) == 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);
            
            char* p = buf + strlen(buf);
            *p ++ = '/';
            
            struct dirent de;
            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;
                }

                char* name = de.name;
                
                if (st.type != T_DIR) {
                    // goto TAR_FILE;
                    if (strcmp(tar, name) == 0) {
                        printf("%s\n", buf);
                    }
                    continue;
                }
                
                if (strcmp(name, ".") && strcmp(name, "..")) {
                    find(buf, tar);
                }
            }

            break;
        default:
            break;
    }

    close(fd);
    return;
}

int main(int argc, char* argv[]) {
    if (argc != 3) {
        fprintf(2, "useage: find path/to/dir file_name\n");
    } else {
        find(argv[1], argv[2]);
    }
    exit(0);
}

xargs

xargs 真正执行的就是其第一个参数中的命令,只要从标准输入流中读入前面命令的输出,然后将这个输出作为真正执行的命令的参数,调用 exec 即可。

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

int main(int argc, char* argv[]) {
    char* xargv[MAXARG] = {};
    for (int i = 1; i < argc; i ++)
        xargv[i - 1] = argv[i];

    char buf[512] = {};
    while (gets(buf, 512)) {
        int len = strlen(buf);
        if (len == 0)
            break;
        if (buf[len - 1] == '\n')
            buf[len - 1] = '\0';
        
        xargv[argc - 1] = buf;
        if (fork() == 0) {
            exec(argv[1], xargv);
        } else {
            wait(0);
        }
    }

    exit(0);
}

标签:char,int,utilities,Lab,Xv6,pipe,close,include,buf
From: https://www.cnblogs.com/FlandreScarlet/p/17978040

相关文章

  • 无涯教程-MATLAB - Octave
    GNUOctave是像MATLAB这样的高级编程语言,它与MATLAB大部分兼容。它也用于数值计算。Octave与MATLAB具有以下共同特征-矩阵是基本数据类型它具有对复数的内置支持它具有内置的数学函数和库它支持用户定义的函数GNUOctave也是可免费重新发行的软件,您可以根据自由软件基金会......
  • Matlab-pcolor绘制二维色温图并修改温度条颜色
    figure(3)pcolor(time,yData',data1.ConVel')shadinginterp;colorbar;color_1=[0,0,1];color_2=[1,1,1];color_3=[1,0,0];num12=45;num23=25;R_mat=[linspace(color_1(1),color_2(1),num12),linspace(color_2(1),color_3(1),num23)];G_mat=[linspace(col......
  • 无涯教程-MATLAB - 变换(Transforms)
    MATLAB提供了用于处理变换的命令,例如Laplace和Fourier变换,转换在科学和工程中用作简化分析并从另一个角度查看数据的工具。例如,傅立叶变换允许我们将表示为时间函数的信号转换为频率函数,拉普拉斯变换使我们能够将微分方程转换为代数方程。MATLAB提供了laplace,傅立叶和fft命......
  • 无涯教程-MATLAB - 多项式(Polynomials)
    MATLAB将多项式表示为行向量,其中包含按降序排序的系数。例如,方程P(x)=x4+7x3-5x+9可以表示为-p=[170-59];判断多项式polyval函数用于以指定值判断多项式。例如,要判断我们先前的多项式p,在x=4处,键入-p=[170-59];polyval(p,4)MATLAB执行上述语句并返......
  • 无涯教程-MATLAB - 代数(Algebra)
    到目前为止,我们已经看到所有示例都可以在MATLAB及其GNU(也称为Octave)中运行,但是对于求解基本的代数方程,MATLAB和Octave几乎没有什么不同,因此我们将尝试在单独的部分中介绍MATLAB和Octave。我们还将讨论代数表达式的分解和简化。MATLAB中代数方程solve函数用于求解代数方程,......
  • 无涯教程-MATLAB - 微积分(Calculus)
    MATLAB提供了多种方法来解决微分和积分问题,求解任意程度的微分方程式以及计算极限,最重要的是,您可以轻松求解复杂函数的图,并通过求解原始函数及其导数来检查图上的最大值,最小值。本章将讨论微积分的问题,在本章中,我们将讨论预演算的概念,即计算函数的极限并验证极限的性质。计算极......
  • 无涯教程-MATLAB - 绘图(Plotting)
    要绘制函数图,您需要执行以下步骤-通过为变量x指定值的范围定义x,为此函数绘制定义函数y=f(x)以plot(x,y)以下示例将演示该概念。让我们用简单的函数y=x绘制x的值范围(从0到100),增量为5。创建一个脚本文件并输入以下代码-x=[0:5:100];y=x;plot(x,y)运行文件时,MAT......
  • 无涯教程-MATLAB - 数据输出
    MATLAB中的数据导出意味着写入文件,MATLAB允许您在另一个读取ASCII文件的应用程序中使用数据,为此,MATLAB提供了几种数据导出选项。有两种方法可以将数字数组导出为定界的ASCII数据文件-使用save函数并指定-ascii限定符使用dlmwrite函数使用保存函数的语法是-savemy_data.......
  • 无涯教程-MATLAB - 字符串(Strings)
    在MATLAB中创建字符串非常简单,实际上,我们已经使用了很多次。例如,您在命令提示符下键入以下内容-my_string='LearnfkPoint'MATLAB将执行上述语句并返回以下输出-my_string=LearnfkPointMATLAB将所有变量视为数组,而字符串则视为字符数组,让我们使用whos命令检查上面创建的变......
  • 无涯教程-MATLAB - 数字(Numbers)
    MATLAB支持各种数字类,包括有符号和无符号整数以及单精度和双精度浮点数,默认情况下,MATLAB将所有数值存储为双精度浮点数。您可以选择将任何数字或数字数组存储为整数或单精度数字,所有数值类型都支持基本数组运算和数学运算。数据类型MATLAB提供以下函数以转换为各种数值数据类......