MIT 6s081 lab1:Xv6 and Unix utilities

Lab1: Xv6 and Unix utilities

作业网址:https://pdos.csail.mit.edu/6.828/2020/labs/util.html

Boot xv6(easy)

下载,启动xv6系统

$ git clone git://g.csail.mit.edu/xv6-labs-2020
Cloning into 'xv6-labs-2020'...
...
$ cd xv6-labs-2020
$ git checkout util
Branch 'util' set up to track remote branch 'util' from 'origin'.
Switched to a new branch 'util'
Build and run xv6:
$ make qemu
To quit qemu type: Ctrl-a x.

sleep(easy)

使用system call sleep.函数(在user/user.h中被声明)来完成

/*
    sleep.c
*/

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

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

    /* 调用sleep函数 */
    sleep(sleep_time);

    exit(0);
}

pingpong(easy)

使用系统调用在一对管道上的两个进程之间“乒乓”一个字节,每个方向一个。父进程应该向子进程发送一个字节;子进程应打印“<pid>:received ping”,其中<pid>是其进程ID,将管道上的字节写入父进程,然后退出;父进程应该读取子进程的字节,打印“<pid>:received-pong”,然后退出。

/*
    pingpong.c
*/

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

int main(int argc, char *argv[])
{
    if(argc != 1) {
        printf("error, usage: <pingpong>\n");
        exit(1);
    }
    int pid;
    /* create pipe */
    int fd[2];
    if(pipe(fd) == -1) exit(1);

    pid = fork();
    char buf[10];

    if(pid == 0) /* child process */
    {
        int pid_this = getpid();
        char *str = "pong";
        read(fd[0], buf, sizeof(buf)); // 阻塞,等待父进程发送
        printf("%d: received %s\n", pid_this, buf);
        write(fd[1], str, strlen(str));
        close(fd[1]);
    }
    else{ /* parent process */
        int pid_this = getpid();
        char *str = "ping";
        write(fd[1], str, strlen(str));
        close(fd[1]);
        wait(0); //等待子进程退出,再去读取

        read(fd[0], buf, sizeof(buf));
        printf("%d: received %s\n", pid_this, buf);
    }
    exit(0);
}

primes (moderate)/(hard)

使用管道通信实现素数筛,求解35以内的素数。

此算法的核心如下:对于任何一级流水线而言,到达当前流水线级的最小数字一定是一个素数,因为在处理之前比它更小的数字时它没有被筛掉,在当前流水线下它也需要作为一个基数去筛掉它在现存数字中的所有倍数,将所有剩下来的数字送入下一级流水线,直到本级流水线只剩下一个数字时,整个筛法结束。

/*
    a concurrent version of prime sieve 并发版本的素数筛
    primes.c
*/

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

static const int N = 35;

int main(int argc, char *argv[])
{
    if(argc != 1) {
        printf("error, usage: <primes>\n");
        exit(1);
    }
    
    int left_fd[2];
    int right_fd[2];
    pipe(left_fd);
    int num = 2;
    for(num = 2; num <= N; num++) write(left_fd[1], &num, sizeof(num));

    while(1)
    {   
        if(fork()) {
            close(left_fd[1]); // 必须关闭父进程的写端
            close(left_fd[0]);
            wait(0);
            exit(0);
        }
        else {
            close(left_fd[1]); // 注意这里,必须关闭子进程的写端,当管道的2个写端都被关闭,read不会发生阻塞,没有数据直接返回
            pipe(right_fd);
            int x = -1, base = -1, cnt = 0;
            while(read(left_fd[0], &x, sizeof(num))){ // 子进程循环读入
                cnt++;
                if(base == -1){
                    base = x; // 第一个数必定是素数
                    printf("prime %d\n", base);
                }
                else{
                    if((x % base) != 0){ // 晒不掉的送入下一层
                        write(right_fd[1], &x, sizeof(num)); 
                    }
                }
                // printf("%d ", x);
            }
            
            if(cnt == 1) exit(0);
            // 这一层与子进程之间的管道是下一层中与父进程之间的管道!
            left_fd[0] = right_fd[0];
            left_fd[1] = right_fd[1];
        }
    }
}

在这里插入图片描述

find (moderate)

它可以在指定的目录下寻找指定名称的文件并打印出来,在编写代码之前可以从ls.c例程中学习如何读取目录信息,当深入到嵌套的文件夹中寻找时,应该使用递归写法。

文件信息结构体:

// 文件信息结构体
// 其中type表明了文件的类型是:文件、目录还是设备
#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
};

目录结构体:

// Directory is a file containing a sequence of dirent structures.
// 所谓目录,就是一系列dirent结构组成的顺序序列
#define DIRSIZ 14

struct dirent {
  ushort inum;
  char name[DIRSIZ];
};

/*
    find.c
*/

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

// 递归查找
void find(char *path, char *name)
{
    int fd;
    //关键在下面这两个结构体里面
    struct stat st; // 获取某个文件的状态
    struct dirent de; //获取目录下的所有项
    if((fd = open(path, 0)) < 0) {
        printf("cannot open %s\n", path);
        exit(1);
    }
    if(fstat(fd, &st) < 0){
        printf("cannot stat %s\n", path);
        close(fd);
        exit(1);
    }
    char buf[256]; // 这个数组不能开太大
    char *p;
    if(st.type == T_DIR)
    {
        if(strlen(path) + 1 + DIRSIZ + 1 > sizeof buf){ // 防止路径太长
            printf("ls: path too long\n");
            exit(1);
        }
        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;
            // 根据前面的path,buf,p组合成当前项的绝对路径,获取其属性
            if(stat(buf, &st) < 0){
                printf("ls: cannot stat %s\n", buf);
                continue;
            }
            if(st.type == T_FILE) { //当前项是文件,则判断
                if(strcmp(de.name, name) == 0) printf("%s\n", buf);
            }
            else{
                // 当前项还是目录,则递归查找
                if(strcmp(de.name, ".") && strcmp(de.name, "..")) // 防止一直递归
                {
                    find(buf, name);
                }
            }
        }
    }
}

int main(int argc, char *argv[])
{
    if(argc != 3){
        printf("error, usage:<find> <path> <name>\n");
        exit(1);
    }
    // read directories
    char path[512], name[512];
    memcpy(path, argv[1], strlen(argv[1]));
    memcpy(name, argv[2], strlen(argv[2]));
    // printf("debug: path = %s\n",path);
    // printf("debug: name = %s\n",name);
    
    // 调用函数find
    find(path, name);

    exit(0);
}

xargs (moderate)

xargs(extensive arguments)是Linux系统中的一个很重要的命令,它一般通过管道来和其他命令一起调用,来将额外的参数传递给命令,这个小问题就是实现自己版本的xargs命令。初次理解xargs命令时还是有点费解的,指导书中的一个例子如下:

$ echo hello too | xargs echo bye
  bye hello too
$

要理解这个例子就将echo hello too | xargs看作一个整体,它本质上是将hello too传递给了xargs,然后经过xagrs的逻辑处理,就会将这些额外传入的参数交给后面的echo命令。我们的任务就是实现这里所谓的xargs的处理逻辑

/*
    xargs.c
*/
#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
#include "kernel/param.h"

char *g_argv[MAXARG];

int main(int argc, char *argv[])
{
    if(argc < 2) {
        printf("error, usage:<xargs> <program>\n");
        exit(1);
    }
    if(argc >= MAXARG) {
        printf("too much argv\n");
        exit(1);
    }
    char c;
    char buf[32];
     
    int i = 0, cnt = 0;
    for(; cnt < argc - 1; cnt++) { 
        g_argv[cnt] = (char*)malloc(sizeof buf); // 要先分配内存,野指针的解引用是未定义的结果
        // g_argv[cnt] = 0;
        // strcpy会对时针进行解引用,然后拷贝
        g_argv[cnt] = strcpy(g_argv[cnt], argv[cnt + 1]);        
    }

    while(read(0, &c, sizeof(c))) // 以字符形式读取完毕
    {
        cnt = argc - 1;
        if(c == '\n' || c == ' '){
            buf[i] = '\0'; // 结束符
            // printf("read: %s\n", buf);
            g_argv[cnt] = (char*)malloc(sizeof buf); // 分配内存
            g_argv[cnt] = strcpy(g_argv[cnt], buf);
            
            cnt++;
            i = 0;
            if(c == '\n') // 说明读完一行命令了,要让子进程去执行
            {   // 此时已经读取完标准输入的argv的
                if(cnt + (argc - 2) >= MAXARG - 1)
                {
                    printf("too much argv\n");
                    exit(1);
                }
                g_argv[cnt] = 0; // 最后一个命令必须为结束符
                if(fork())
                {   // 父进程等待子进程结束,等待完处理下一条命令
                    wait(0);
                }
                else{ // 子进程
                    exec(argv[1], g_argv);
                    exit(0);
                }
            }
        }
        else {
            buf[i++] = c; // 不是空格也不是换行符,那就读取字符
        }
    }
    
    exit(0);

}

调试方式

首先make qemu-gdb CPUS=1,启动gdb-server

然后在另一个终端中(启动gdb客户端)使用gdb-multiarch -q kernel/kernel(kernel/kernel表示要gdb的程序)

进入gdb后

  • b:设置断点
  • c:运行
  • n:单步运行
  • s:进入函数内部

使用gdb的layout split模式可以看到gdb要执行的下一条指令是什么,断点具体在什么位置

提交

创建time.txt,写入耗时

make grade

结果:

$ make qemu-gdb
sleep, no arguments: OK (2.8s) 
== Test sleep, returns == 
$ make qemu-gdb
sleep, returns: OK (0.4s) 
== Test sleep, makes syscall == 
$ make qemu-gdb
sleep, makes syscall: OK (1.0s) 
== Test pingpong == 
$ make qemu-gdb
pingpong: OK (1.0s) 
== Test primes == 
$ make qemu-gdb
primes: OK (1.1s) 
== Test find, in current directory == 
$ make qemu-gdb
find, in current directory: OK (1.0s) 
== Test find, recursive == 
$ make qemu-gdb
find, recursive: OK (1.1s) 
== Test xargs == 
$ make qemu-gdb
xargs: OK (1.1s) 
== Test time == 
time: OK 
Score: 100/100

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/326016.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【dc-dc】世微AP5127平均电流型LED降压恒流驱动器 双色切换的LED灯驱动方案

这是一款双色切换的LED灯方案&#xff0c;12-50V 降压恒流,输出&#xff1a;6V 2.5A ​ 这是一款PWM工作模式 , 高效率、 外围简单、内置功率管&#xff0c;适用于 输入的 高 精度降压 LED 恒流驱动芯片。输出大功率可 达 25W&#xff0c;电流 2.5A。 可实现全亮/半亮功能切换…

Linux 设备树详解

1、概述 设备树&#xff08; Device Tree&#xff09;是一种描述硬件的数据结构&#xff0c;在操作系统&#xff08; OS&#xff09;引导 阶段进行设备初始化的时候&#xff0c;数据结构中的硬件信息被检测并传递给操作系统 最早诞生于 Open Firmware&#xff0c; Flattened De…

【MySQL】:DDL数据库定义与操作

&#x1f3a5; 屿小夏 &#xff1a; 个人主页 &#x1f525;个人专栏 &#xff1a; MySQL从入门到进阶 &#x1f304; 莫道桑榆晚&#xff0c;为霞尚满天&#xff01; 文章目录 &#x1f4d1;前言一. SQL的分类二. DDL数据库操作2.1 查询所有数据库2.2 查询当前数据库2.3 创建数…

测量鼠标DPI的三种方法,总有一种适合你

DPI(dots per inch)代表每英寸点数,是一种用于各种技术设备(包括打印机)的测量方法,但对于鼠标来说,指的是鼠标在桌面上移动1英寸的距离的同时,鼠标光标能够在屏幕上移动多少“点”。 许多游戏鼠标都有按钮,可以让你在玩游戏时动态切换DPI,但如果你不知道鼠标的DPI怎…

x-cmd pkg | duf - df 命令的现代化替代品

目录 简介用户首次快速实验指南技术特点竞品和相关作品进一步探索 简介 Duf &#xff08;Disk Usage/Free Utility&#xff09;是一个磁盘分析工具。其直观的输出和多样化的自定义选项&#xff0c;帮助用户更好地管理和优化存储资源。 用户首次快速实验指南 使用 x duf 即可自…

为什么大厂暴力裁员确很少有技术人敢举报?

最近几年大厂暴力裁员的事件太多了&#xff0c;但是确鲜有当事人出来举报&#xff0c;这个又是为什么呢&#xff1f;本文从中立的角度&#xff0c;来给大家来分析一下。 大厂会包装&#xff0c;将暴力裁员包装为KPI优化 KPI这个玩意&#xff0c;其实是蛮扯淡的&#xff0c;也…

重磅!30余所985高校全面取消博士统考!

2024年博士招生&#xff0c;又有“双一流”高校取消统考。 近日&#xff0c;各大高校正在陆续发布《2024年博士研究生招生简章》&#xff0c;其中南昌大学的博士招生方式引起了广泛关注。据悉&#xff0c;南昌大学将全面实行“申请—考核”制选拔方式&#xff0c;适用于直接攻…

【Linux】自定义shell

👑作者主页:@安 度 因 🏠学习社区:安度因 📖专栏链接:Linux 文章目录 获取命令行前置字段命令行输入解析命令行普通指令的执行子进程执行命令指令类型判断 && 内建命令总结 &&a

什么是OV证书?

OV证书是一种经过严格身份验证的SSL/TLS证书&#xff0c;相较于基础的域名验证(DV)证书&#xff0c;它的验证过程更为深入和全面。在颁发OV证书前&#xff0c;证书颁发机构(CA)不仅会验证申请者对域名的所有权&#xff0c;还会对企业或组织的身份进行严格的审查&#xff0c;包括…

京东年度数据报告-2023全年度饮料十大热门品牌销量(销额)榜单

2023年度&#xff0c;饮料市场的销售相较去年呈下滑状态。根据鲸参谋电商数据分析平台的相关数据显示&#xff0c;京东平台上饮料市场的年度销量约9100万&#xff0c;同比下滑约9%&#xff1b;销售额约53亿&#xff0c;同比下滑约3%。另外&#xff0c;天猫平台上饮料市场的年度…

上门按摩系统:科技与传统融合的新体验

在快节奏的现代生活中&#xff0c;人们越来越重视身心健康。传统的按摩方式虽然深受喜爱&#xff0c;却常因时间、地点的限制而无法满足需求。此时&#xff0c;上门按摩系统应运而生&#xff0c;将科技与传统的按摩技艺完美结合&#xff0c;为用户提供更便捷、个性化的服务。 上…

基于SSM的流浪动物救助网站的设计与实现-计算机毕业设计源码82131

摘 要 随着生活水平的持续提高和家庭规模的缩小&#xff0c;宠物已经成为越来越多都市人生活的一部分&#xff0c;随着宠物的增多&#xff0c;流浪的动物的日益增多&#xff0c;中国的流浪动物领养和救助也随之形成规模&#xff0c;同时展现巨大潜力。本次系统的是基于SSM框架的…

使用Sqoop的并行处理:扩展数据传输

使用Sqoop的并行处理是在大数据环境中高效传输数据的关键。它可以显著减少数据传输的时间&#xff0c;并充分利用集群资源。本文将深入探讨Sqoop的并行处理能力&#xff0c;提供详细的示例代码&#xff0c;以帮助大家更全面地了解和应用这一技术。 Sqoop的并行处理 在开始介绍…

Java工具类——json字符串格式化处理

在我们拿到一团未经格式化的json字符串时&#xff0c;非常不方便查看&#xff0c;比如这样 {"APP_HEAD": {"TOTAL_NUM": "-1","PGUP_OR_PGDN": "0"},"SYS_HEAD": {"RET": [{"RET_CODE": &qu…

Puppeteer让你网页操作更简单(2)抓取数据

Puppeteer让你网页操作更简单(1)屏幕截图】 示例2 —— 让我们抓取一些数据 现在您已经了解了Headless Chrome和Puppeteer的工作原理基础知识,让我们看一个更复杂的示例,其中我们实际上可以抓取一些数据。 首先,请查看此处的Puppeteer API文档。如您所见,有大量不同的方法我…

el-select中多选回显数据后没法重新选择和更改

<el-form-item label"展示内容" prop"videoId"><el-select class"modal-input" multiple v-model"form.videoId"><el-optionclass"modal-input"v-for"(item) in videoIdTypes":key"item.id&q…

直播产品痛点话术

一、用户需求分析 为了更好地满足用户需求&#xff0c;我们对市场进行了深入的调研。发现主播们在直播过程中面临着多方面的挑战&#xff0c;如产品功能、质量、价格、安全性等方面的需求。 二、产品功能不足 当前市场上的主播产品存在功能不足的问题。例如&#xff0c;一些…

法规更新美国玩具标准ASTM F963-17有更新,最新标准为ASTM F963-23

美国材料试验协会 (ASTM)在10月13日发布了新的玩具安全标准&#xff1a;ASTM F963-23&#xff0c;ASTM F963-17美国联邦法规16 CFR 1250还在使用当中&#xff0c;出口美国的玩具的厂商要引起重视。 ASTM F963-17是什么标准&#xff1f; ASTM F963-17是美国玩具检测标准&#…

postman 简单测试(一)

1.postman官网 Postman API Platform 2.研究了一下postman 一些简单的功能&#xff0c;自己做个记录&#xff0c;同时希望能节约点测试时间。 2.1新建一个 collections 长期测的话&#xff0c;最好注册一个账号&#xff0c;开放更多功能。 2.2新建一个请求 后端要先搭建起来…

网络部署实战具体学习内容总结

网络部署实战具体学习内容总结 &#x1f4bb;网络部署实战课程通常旨在教授学生如何规划、配置、维护和优化计算机网络。这些课程涵盖了广泛的主题&#xff0c;以确保学生具备网络部署和管理所需的技能。 网络部署实战课程具体学习内容&#x1f447; 1️⃣网络架构设计及网络原…