【MIT 6.S081】Lab1: Xv6 and Unix utilities

news2024/11/17 23:26:52

Util

  • 概述
  • ```sleep```
  • ```pingpong```
  • ```primes```
  • ```find```
  • ```xargs```

本Lab包括五个应用程序的实现,初步熟悉系统调用接口。
用时约8h(我太菜辣)

本Lab包括五个简单程序的实现,初步熟悉系统调用接口。
笔者用时约6h(我太菜辣)

概述

根据文档说明,我们需要把写的每个程序文件放在user文件夹下,并且在MakeFileUPROGS添加相应的程序名,这样子就可以在qemu中直接用命令行指令调用相应的程序啦。如下图所示。
在这里插入图片描述

sleep

sleep程序接收一个参数,调用库函数sleep进行睡眠即可,没啥好说滴。

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

int main(int argc, char* argv[]) 
{
    if (argc != 2) { 
        fprintf(2, "usage: sleep time\n");
        exit(1);
    }

    sleep(atoi(argv[1]));

    exit(0);
}

pingpong

该程序的要求就是创建一个子进程,父进程为子进程发送一个字节,子进程接收到字节之后,打印ping,向父进程发送一个字节,父进程接收到该字节之后打印pong,程序结束。
做法就是打开两个管道,一个用于父进程写子进程读,另一个则相反。

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

int main(int argc, char* argv[]) 
{
    if (argc != 1) { 
        fprintf(2, "usage: pingpong\n");
        exit(1);
    }

    int p_father_to_child[2];
    int p_child_to_father[2];
    if (pipe(p_father_to_child) == -1 || pipe(p_child_to_father) == -1) {
        fprintf(2, "failed to open pipe\n");
        exit(1);
    }

    char buf = 'C';
    int exit_state = 0;

    // child process
    if (fork() == 0) {
        close(p_father_to_child[1]);
        close(p_child_to_father[0]);

        if (read(p_father_to_child[0], &buf, 1) != 1) {
            fprintf(2, "failed to read pipe in child\n");
            exit_state = 1;
        }

        fprintf(1, "%d: received ping\n", getpid());

        if (write(p_child_to_father[1], &buf, 1) != 1) {
            fprintf(2, "failed to write pipe in child\n");
            exit_state = 1;
        }

        exit(exit_state);
    }

    // father process
    close(p_father_to_child[0]);
    close(p_child_to_father[1]);

    if (write(p_father_to_child[1], &buf, 1) != 1) {
        fprintf(2, "failed to write pipe in parent\n");
        exit_state = 1;
    }

    wait(0);
    
    if (read(p_child_to_father[0], &buf, 1) != 1) {
        fprintf(2, "failed to read pipe in parent\n");
        exit_state = 1;
    }

    fprintf(1, "%d: received pong\n", getpid());

    exit(exit_state);
}

primes

该题目要求我们写一个并发运行的素数筛,其思想大致如下:
建立若干个进程,前一个进程的输出为后一个进程的输入(用管道进行连接);
第一个进程没有输入,向管道直接输出2~35;第二个进程以第一个进程的输出作为输入(2~35),向终端输出2(素数),并筛掉2的倍数,向下一个管道输出非2倍数的数,以此类推,直到没有数输出为止即可。

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

#define RD 0
#define WR 1
const uint INT_SIZE = sizeof(int);

void getprime(int left_p[]) {
    // check if there has a prime
    int prime, i;
    if (read(left_p[RD], &prime, INT_SIZE) == 0) {
        close(left_p[RD]);
        exit(0);
    }

    fprintf(1, "prime %d\n", prime);
    
    // create the pipe to the right neighbor
    int right_p[2];
    pipe(right_p);

    // read the data from left neighbor
    while (read(left_p[RD], &i, INT_SIZE) != 0) {
        if (i % prime != 0) 
            write(right_p[WR], &i, INT_SIZE);
    }
    close(left_p[RD]);
    close(right_p[WR]);

    if (fork() == 0) {
        getprime(right_p);
    } else {
        close(right_p[RD]);
        wait(0);
    }

}

int main(int argc, char* argv[]) 
{
    if (argc != 1) { 
        fprintf(1, "usage: primes\n");
        exit(1);
    }

    int p[2], i;
    pipe(p);

    for (i = 2; i <= 35; i ++ ) {
        write(p[WR], &i, INT_SIZE);
    }
    close(p[WR]);

    if (fork() == 0) {
        getprime(p);
    } else {
        close(p[RD]);
        wait(0);
    }

    exit(0);
}

find

该题目要求写一个程序,在指定的目录中查找与给定文件名相同的文件,若查找到了则输出文件路径(从指定目录开始的路径)。
根据提示,查看user/ls.c文件中ls程序的实现,其中使用fstat函数查看当前路径的类型(目录或文件)
类似的,我们实现的文件查找也使用fstat函数判断路径类型,如果当前路径是文件,则与给定的文件名比较(相等则输出);如果当前路径是目录,则遍历目录中的内容进行递归查找(注意不要对...递归)

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

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

    if ((fd = open(path, 0)) < 0) {
        fprintf(2, "find: cannot open %s\n", path);
        exit(1);
    }

    if (fstat(fd, &st) < 0) {
        fprintf(2, "find: cannot stat %s\n", path);
        close(fd);
        exit(1);
    }

    if (st.type == T_FILE) {
        fprintf(2, "usgae: find <directory> <filename>\n");
        close(fd);
        exit(1);
    }
    
    if (strlen(path) + 1 + DIRSIZ + 1 > sizeof buf) {
        fprintf(2, "find: path too long\n");
        close(fd);
        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;

        if (stat(buf, &st) < 0) {
            fprintf(2, "find: cannot stat %s\n", buf);
            continue;
        }

        if (st.type == T_FILE) {
            if (strcmp(p, filename) == 0) 
                fprintf(1, "%s\n", buf);
        } else if (st.type == T_DIR && strcmp(p, ".") != 0 && strcmp(p, "..") != 0) {
            find_file(buf, filename);
        }

    }
    close(fd);
}

int main(int argc, char* argv[]) 
{

    if (argc != 3) {
        fprintf(2, "usgae: find <directory> <filename>\n");
        exit(1);
    }

    find_file(argv[1], argv[2]);

    exit(0);
}

xargs

该题要求实现一个程序,每从标准输入中读取一行,就调用一次命令(参数是命令)。
这个其实不难(但是我一开始把buf开大了,调了一个小时),大概就是从标准输入读取一行,然后分割成若干个命令行参数,创建一个子进程后使用ecex执行命令即可。

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

#define LINE 1024

int read_line(int fd, char* buf, int len) {
    char* p = buf;
    int i = 0;

    while (i < len - 1) {
        int res = read(fd, p, 1);
        if (res == -1) return -1;
        else if (res == 0)
            break;

        p ++;
        i ++;
        if (*(p - 1) == '\n') break;
    }
    *p = 0;
    return i;
}

int main(int argc, char* argv[])
{
    if (argc == 1) {
        fprintf(2, "usage: xargs command [args]\n");
        exit(1);
    }

    char* args[MAXARG + 1];
    memset(args, 0, sizeof args);
    int args_num = argc - 1;
    int i, j, k;

    for (i = 1; i < argc; i ++ )
        args[i - 1] = argv[i];        

    char buf[LINE];
    int res;

    while ( (res = read_line(0, buf, LINE)) != 0 ) {
        if (res == -1) {
            fprintf(2, "xargs: cannot read line from standard input\n");
            exit(1);
        }

        if (buf[res - 1] != '\n' && res == LINE) {
            fprintf(2, "xargs: line too long\n");
            exit(1);
        }

        // split the args
        buf[-- res] = '\0';
        i = 0, k = args_num;
        while (i < res) {
            if (buf[i] == ' ') i ++;
            else {
                j = i;
                while (j < res && buf[j] != ' ')
                    j ++;

                // buf[i ~ j - 1] is an argument
                if (k == MAXARG) {
                    fprintf(2, "xargs: too many arguments\n");
                }
                args[k] = (char*)malloc(sizeof(char) * (j - i + 1));
                memcpy(args[k], buf + i, j - i);
                args[k][j - i + 1] = '\0';
                k ++;

                i = j;
            }
        }

        if (fork() == 0) {
            exec(args[0], args);
            fprintf(2, "xargs: command %s not found\n", args[0]);
        }

        wait(0);
        // free the malloc space
        for (i = args_num; i < k; i ++ ) 
            free(args[i]), args[i] = 0;
    }

    exit(0);
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

mysql数据库之全局锁

锁是计算机协调多个进程或线程并发访问某一资源的机制。在数据库中&#xff0c;除传统的计算资源&#xff08;CPU、RAM、I/O&#xff09;的争用以外&#xff0c;数据也是一种供许多用户共享的资源。如何保证数据并发访问的一致性、有效性是所有数据库必须解决的一个问题&#x…

【Day2】Numpy简单入门基础

NumPy 简单入门基础 我的另一篇文章 &#xff1a; Numpy介绍-深度学习&#xff1a;Numpy介绍-深度学习&#xff08;Numpy介绍深度学习使用看这些足够了&#xff09; import numpy as npmy_array np.array([1, 2, 3, 4, 5]) print(my_array)[1 2 3 4 5]print(my_array.shape)…

Kafka 多线程消费者

Kafka 多线程消费者多线程方案Kafka 0.10.1.0 后&#xff0c;Kafka Consumer 变为双线程的设计 : 用户主线程 : 启动 Consumer 的 main心跳线程 (Heartbeat Thread) : 定期对 Broker 发送心跳请求&#xff0c;探测消费者的存活性 (liveness&#xff09;将心跳频率与主线程处理…

MQTT协议-取消订阅和取消订阅确认

MQTT协议-取消订阅和取消订阅确认 客户端向服务器取消订阅 取消订阅的前提是客户端已经通过CONNECT报文连接上服务器&#xff0c;并且订阅了一个主题 UNSUBSCRIBE—取消订阅 取消订阅的报文同样是由固定报头可变报头有效载荷组成 固定报头由两个字节组成&#xff0c;第一个…

2023年,当我们谈论架构时,我们要聊什么

架构是一个非常宽泛的话题&#xff0c;从组织结构上来说&#xff0c;涉及到前端、后端、运维&#xff1b;从软件设计上来说&#xff0c;涉及到需求分析、设计、编码、测试&#xff1b;从物理结构上来说&#xff0c;涉及到CDN、负载均衡、网关、服务器、数据库。当前一些架构方面…

奇淫技巧:阅读源码时基于一组快捷键,让我们知道身在何方!

一个十分蛋疼的问题 在我们阅读框架底层源码的时候&#xff0c;我们往往会一个方法一个方法的往下翻&#xff0c;翻了很久很快就会有这样的灵魂拷问&#xff1a;我从那个类&#xff08;方法&#xff09;来&#xff0c;我要到哪个&#xff08;类&#xff09;方法中去。这个时候…

RK3568平台开发系列讲解(显示篇) DRM显示系统组成分析

🚀返回专栏总目录 文章目录 一、DRM Framebuffer二、CRTC三、Planes四、Encoder五、Connector沉淀、分享、成长,让自己和他人都能有所收获!😄 📢让我们分析一下绿框中的五个部件,以及他们的联动。 一、DRM Framebuffer 与 framebuffer一样,是一片存放图像的内存区域,…

敏捷开发还需要PRD吗

一、PRD有什么用 prd提升与RD或者未来接手人的沟通效率 二、为什么会有PRD 首先来说说为什么会有PRD文档。 1、稍微大一点的团队产品经理未必能向每个人传达产品需求&#xff0c;这就需要有一个文档的形式来向项目的所有成员来传达需求&#xff0c;这就是文档的来源。 2、由…

Python读写mdb文件的实战代码

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。喜欢通过博客创作的方式对所学的知识进行总结与归纳,不仅形成深入且独到的理…

MySQL的分库分表?通俗易懂

1- 为什么要分库分表 如果一个网站业务快速发展&#xff0c;那这个网站流量也会增加&#xff0c;数据的压力也会随之而来&#xff0c;比如电商系统来说双十一大促对订单数据压力很大&#xff0c;Tps十几万并发量&#xff0c;如果传统的架构&#xff08;一主多从&#xff09;&a…

【数据结构】解决顺序表题的基本方法

&#x1f680;write in front&#x1f680; &#x1f4dc;所属专栏&#xff1a;> 初阶数据结构 &#x1f6f0;️博客主页&#xff1a;睿睿的博客主页 &#x1f6f0;️代码仓库&#xff1a;&#x1f389;VS2022_C语言仓库 &#x1f3a1;您的点赞、关注、收藏、评论&#xff0…

java 4 (面向对象上)

java——面向对象&#xff08;上&#xff09; 目录java——面向对象&#xff08;上&#xff09;面向对象的思想概述类的成员&#xff08;1-2&#xff09;&#xff1a;属性和方法对象的内存解析类中属性的使用类中方法的使用1.举例&#xff1a;2.声明方法&#xff1a;3.说明4.re…

计算机网络基础知识点【1】

文章目录计算机网络第一章 计算机网络参考模型1.计算机网络为什么需要分层&#xff1f;1.1 分层思想1.2 分层好处2.OSI七层模型2.1 OSI七层模型总结2.2 OSI七层工作原理2.3 数据封装与解封装2.4 计算机网络常用协议3.TCP/IP参考模型3.1 什么是TCP/IP协议3.2 TCP/IP协议族的组成…

扬帆优配|引活水 增活力 促转型 创业板助力实体经济高质量发展

立异就是生产力&#xff0c;企业赖之以强&#xff0c;国家赖之以盛。全面注册制变革持续开释立异生机。日前&#xff0c;创业板公司已开端连续公布2022年度年度报告和2023年第一季度成绩预告&#xff0c;从频频传来的“喜报”中可窥见立异驱动开展战略下新兴工业的强劲开展态势…

jvm之堆上的GC和分代思想解读

堆上的GC JVM在进行GC时&#xff0c;并非每次都对上面三个内存区域一起回收的&#xff0c;大部分时候回收的都是指新生代。 性能调优主要就是减少GC&#xff0c;GC线程执行引发STW会让用户线程停止&#xff0c;阻碍了用户线程的执行&#xff0c;并且majorGC和fullGC阻碍的时间…

内卷把同事逼成了“扫地僧”,把Git上所有面试题整理成足足24W字Java八股文

互联网大厂更多的是看重学历还是技术&#xff1f;毫无疑问&#xff0c;是技术&#xff0c;技术水平相近的情况下&#xff0c;肯定学历高/好的会优先一点&#xff0c;这点大家肯定都理解。说实话&#xff0c;学弟学妹们找工作难&#xff0c;作为面试官招人也难呀&#xff01;&am…

TypeScript深度剖析:Vue项目中应用TypeScript?

一、前言 与link类似 在VUE项目中应用typescript&#xff0c;我们需要引入一个库vue-property-decorator&#xff0c; 其是基于vue-class-component库而来&#xff0c;这个库vue官方推出的一个支持使用class方式来开发vue单文件组件的库 主要的功能如下&#xff1a; metho…

【刷题笔记】之滑动窗口(长度最小的子数组、水果成篮、最小的覆盖子串)

滑动窗口模板//滑动窗口模板&#xff1a;注意使用滑动窗口方法&#xff0c;使用一个 for(while) 循环中的变量是用来控制终止位置的//最小滑窗&#xff1a;给定数组 nums&#xff0c;定义滑动窗口的左右边界 i、j&#xff0c;求满足某个条件的滑窗的最小长度 for(j 0; j < …

华为OD机试题,用 Java 解【寻找身高相近的小朋友】问题

华为Od必看系列 华为OD机试 全流程解析+经验分享,题型分享,防作弊指南)华为od机试,独家整理 已参加机试人员的实战技巧华为od 2023 | 什么是华为od,od 薪资待遇,od机试题清单华为OD机试真题大全,用 Python 解华为机试题 | 机试宝典使用说明 参加华为od机试,一定要注意不…

SpringMVC源码:视图解析器

参考资料&#xff1a; 《SpringMVC源码解析系列》 《SpringMVC源码分析》 《Spring MVC源码》 写在开头&#xff1a;本文为个人学习笔记&#xff0c;内容比较随意&#xff0c;夹杂个人理解&#xff0c;如有错误&#xff0c;欢迎指正。 前文&#xff1a; 《SpringMVC源码&a…