【MIT 6.S081】2020, 实验记录(1),Lab: Xv6 and Unix utilities

news2025/1/19 11:39:18

目录

    • 实验准备
    • Tasks
      • Task 1: Boot xv6
      • Task 2: sleep
      • Task 3: pingpong
      • Task 4: primes
      • Task 5: find

实验准备

这个 lab 用来学习尝试如何通过 system call 来实现常见的 shell 命令行程序,比如 lssleepxargs 等。

  • 实验官网

可以使用 docker 搭建实验环境:

docker pull debian:bullseye
docker run -it --name mit6.s081 -d debian:bullseye /bin/bash

然后按照实验官网的介绍,在 git 下载源代码并启动。

Tasks

Task 1: Boot xv6

这个 task 就是在 git 上下载源代码,并启动 xv6 系统:

$ make qemu

成功后就可以看到 OS 成功启动。

Task 2: sleep

本 task 以及接下来的 task,都是在 /user 目录下实现用户级程序。

这个 task 新建一个 user/sleep.c,并通过调用 system call 来实现睡眠的功能,代码较为简单:

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

int
mian(int argc, char *argv[])
{
    if (argc < 2) {
        fprintf(2, "Usage: sleep ticks...\n");
        exit(1);
    }

    int ticks = atoi(argv[1]);
    sleep(ticks);  // 系统调用的 sleep,声明在 `user/user.h` 中
    exit(0);
}

完成后在 Makefile 中的 UPROGS 里添加上 sleep。

测试:

./grade-lab-util sleep

sleep task

Task 3: pingpong

通过该 task 学会 fork 一个子进程,并实现父进程与子进程的通信。

我们需要实现 fork 一个子进程,并让父进程向子进程发送一个字节,然后子进程再向父进程发送一个字节。

关键技术细节:

  • 使用 pipe 函数建立用于进程间通信的通道:
int fds[2];
pipe(fds);

这里 fds[0] 用于 read,fds[1] 用于 write,每个进程在使用完某个 fd 后需要 close 掉 fd。

  • read() 函数的行为:在另一方未关闭写的 fd 时,自己读取且没有更多消息时会阻塞住;而在另一方关闭了写的 fd 且自己没有更多消息可以读时,会立刻返回 0.

代码实现:

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


int
main(int argc, char *argv[])
{
    int fds[2], pid, n, xstatus;
    enum { BYTE_SZ=1 };
    if (pipe(fds) != 0) {
        printf("pipe() failed\n");
        exit(1);
    }
    pid = fork();
    if (pid > 0) {  // parent proc
        // 向子进程发送一个字节
        char parent_buf[BYTE_SZ];
        if (write(fds[1], "x", BYTE_SZ) != BYTE_SZ) {
            printf("pingpong oops 1\n");
            exit(1);
        }
        // 等待子进程结束
        wait(&xstatus);
        if (xstatus != 0) {
            exit(xstatus);
        }
        // 读取子进程发送过来的字节
        while ((n = read(fds[0], parent_buf, BYTE_SZ)) > 0) {
            if (parent_buf[0] != 'x') {
                printf("pingpong oops 2\n");
                exit(1);
            }
            printf("%d: received pong\n", getpid());
            close(fds[0]);
            close(fds[1]);
            exit(0);
        }
    } else if (pid == 0) {  // child proc
        // 等待读取父进程发送的字节
        char child_buf[BYTE_SZ];
        while ((n = read(fds[0], child_buf, BYTE_SZ)) > 0) {
            if (child_buf[0] != 'x') {
                printf("pingpong oops 2\n");
                exit(1);
            }
            printf("%d: received ping\n", getpid());
            // 向父进程发送一个字节
            if (write(fds[1], "x", BYTE_SZ) != BYTE_SZ) {
                printf("pingpong oops 2\n");
                exit(1);
            }
            close(fds[0]);
            close(fds[1]);
            exit(0);
        }
    } else {
        printf("fork() failed\n");
        exit(1);
    }
    exit(0);
}

测试:

在这里插入图片描述

Task 4: primes

这里需要使用 fork 子进程和进程间通信的技术实现 2~35 以内质数的筛选。

思路如下:

质数筛选

大致就是:

  • 第一个进程将 2~35 写入管道
  • 然后 fork 第二个进程,逐个从管道中读出数字,再将符合条件的数字送入下一个管道给第三个进程
  • 第三个进程类似…

代码实现如下:

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


#define INT_SIZE (sizeof(int))
#define MAX_LIMIT  35
#define READ_END 0
#define WRITE_END 1


int
main(int argc, char *argv[])
{
    int fds1[2], fds2[2], n, p, xstatus, pid;
    int *left_fds = fds1;  // 左通道
    int *right_fds = fds2; // 右通道
    if (pipe(left_fds) != 0 || pipe(right_fds) != 0) {
        printf("pipe() failed\n");
        exit(1);
    }
    // feed numbers
    for (int i = 2; i < MAX_LIMIT; ++i) {
        write(left_fds[WRITE_END], &i, INT_SIZE);
    }
    close(left_fds[WRITE_END]);
    int first_loop = 1;
    while (1) {
        int is_success = read(left_fds[READ_END], &n, INT_SIZE);  // read from left
        if (is_success == 0) {   // if read end
            close(left_fds[READ_END]);
            close(right_fds[READ_END]);
            close(right_fds[WRITE_END]);
            if (first_loop != 1) {
                wait(&xstatus);
                exit(xstatus);
            } else {
                exit(0);
            }
        }
        // 如果是第一次进入 Loop,则需要打印 prime 并创建一个子进程
        if (first_loop == 1) {
            pid = fork();
            if (pid == 0) {  // child proc
                first_loop = 1;
                close(left_fds[READ_END]);
                close(left_fds[WRITE_END]);
                int *temp = left_fds;
                left_fds = right_fds;
                right_fds = temp;
                if (pipe(right_fds) != 0) {
                    printf("pipe() failed\n");
                    exit(1);
                }
                close(left_fds[WRITE_END]);
                continue;
            } else if (pid > 0) {  // parent proc
                first_loop = 0;
                p = n;
                printf("prime %d\n", p);
                continue;
            } else {
                printf("fork() failed\n");
                exit(1);
            }
        } else {
            if ((n % p) != 0) {
                write(right_fds[WRITE_END], &n, INT_SIZE);
            }
        }
    }
}

测试:

质数筛选测试

Task 5: find

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

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

相关文章

全志R128 SDK架构与目录结构

R128 S2 是全志提供的一款 M33(ARM)C906(RISCV-64)HIFI5(Xtensa) 三核异构 SoC&#xff0c;同时芯片内部 SIP 有 1M SRAM、8M LSPSRAM、8M HSPSRAM 以及 16M NORFLASH。本文档作为 R128 FreeRTOS SDK 开发指南&#xff0c;旨在帮助软件开发工程师、技术支持工程师快速上手&…

MathType2024MAC苹果电脑版本下载安装图文教程

在数学和科学的世界里&#xff0c;表达精确的方程式和化学公式是至关重要的。MathType作为一款及其优秀且有全球影响力的数学公式编辑器&#xff0c;让这一切变得触手可及。MathType Mac版已全新升级&#xff0c;作为Microsoft Word和PowerPoint的Add-In插件&#xff0c;为您的…

项目使用PowerJob

新一代的定时任务框架——PowerJob 简介 PowerJob是基于java开发的企业级的分布式任务调度平台&#xff0c;与xxl-job一样&#xff0c;基于web页面实现任务调度配置与记录&#xff0c;使用简单&#xff0c;上手快速&#xff0c;其主要功能特性如下&#xff1a; 使用简单&…

CEC2017(Python):七种算法(PSO、RFO、DBO、HHO、SSA、DE、GWO)求解CEC2017

一、7种算法简介 1、粒子群优化算法PSO 2、红狐优化算法RFO 3、蜣螂优化算法DBO 4、哈里斯鹰优化算法HHO 5、麻雀搜索算法SSA 6、差分进化算法DE 7、灰狼优化算法GWO 二、CEC2017简介 参考文献&#xff1a; [1]Awad, N. H., Ali, M. Z., Liang, J. J., Qu, B. Y., &am…

华为云Stack 8.X流量模型分析(六)

八、基础云专线流量模型分析 ​ 华为官方对云专线定义是&#xff1a;用户数据中心通过运营商的物理专线&#xff08;MPLS/VPN&#xff0c;以太专线&#xff09;访问云内资源&#xff0c;云内资源呈现真实IP&#xff0c;通过设置的专线路由实现三层互通。 ​ 通过云专线直接访…

LeetCode(36)有效的数独 ⭐⭐

请你判断一个 9 x 9 的数独是否有效。只需要 根据以下规则 &#xff0c;验证已经填入的数字是否有效即可。 数字 1-9 在每一行只能出现一次。数字 1-9 在每一列只能出现一次。数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。&#xff08;请参考示例图&#xff09; 注…

ssm基于web的网络游戏交易平台信息管理系统的设计与实现论文

摘 要 传统办法管理信息首先需要花费的时间比较多&#xff0c;其次数据出错率比较高&#xff0c;而且对错误的数据进行更改也比较困难&#xff0c;最后&#xff0c;检索数据费事费力。因此&#xff0c;在计算机上安装网络游戏交易平台软件来发挥其高效地信息处理的作用&#x…

SecOC中新鲜度值和MAC都按照完整的值来生成,但是在发送和认证的时候只会截取一部分。这边截取的部分一般取多长?由什么参数设定?

新鲜度值(Freshness Value, FV)和消息验证码(Message Authentication Code, MAC)是SecOC协议中用于保证数据的真实性和新鲜度的重要信息。它们的长度取决于不同的因素,如加密算法、安全级别、通信带宽等。 一般来说,FV和MAC的长度越长,安全性越高,但也会占用更多的通信…

Kibana 自定义索引连接器告警

一、 创建索引 PUT ipu-cbs-warning-info{"settings" : {"number_of_shards" : 1},"mappings" : {"properties" : {"timestamp": {"type": "date"},"rule_id" : { "type" : "…

面试官:CSS3新增了哪些新特性?

面试官&#xff1a;CSS3新增了哪些新特性&#xff1f; 一、是什么 css&#xff0c;即层叠样式表&#xff08;Cascading Style Sheets&#xff09;的简称&#xff0c;是一种标记语言&#xff0c;由浏览器解释执行用来使页面变得更美观 css3是css的最新标准&#xff0c;是向后兼…

十、基本对话框大集合(Qt5 GUI系列)

目录 一、设计需求 二、实现代码 三、代码解析 四、总结 一、设计需求 Qt提供了很多标准的对话框。例如标准文件对话框(QFileDialog)、标准颜色对话框(QColorDialog)、标准字体对话框 (QFontDialog)、标准输入对话框 (QInputDialog) 及消息对话框 (QMessageBox)。本文展示各…

编写.NET的Dockerfile文件构建镜像

创建一个WebApi项目&#xff0c;并且创建一个Dockerfile空文件&#xff0c;添加以下代码&#xff0c;7.0代表的你项目使用的SDK的版本&#xff0c;构建的时候也需要选择好指定的镜像tag FROM mcr.microsoft.com/dotnet/aspnet:7.0 AS base WORKDIR /app EXPOSE 80 EXPOSE 443F…

[论文笔记] Megtron_LM 0、报错:vscode调试无法传进去参数 launch.json文件获取args参数

解决方法&#xff1a; 配置好launch.json文件后&#xff0c;应该点运行和调试里面的运行按钮。而不是直接点文件右上角的debug。 可以看到terminal中&#xff0c;如果没有正常加载launch.json&#xff0c;则参数中没有args的参数。 如果正常加载&#xff0c;可以看到args的很多…

docker镜像仓库详解(Docker Registry)

本片文章主要是对docker的镜像仓库进行了详解。其中包含了一些常用了 docker 指令&#xff0c;通过举例进行详解。也详细解释了镜像仓库的工作机制和常见的镜像仓库。也实际拉去和运行了一些镜像。希望本篇文章会对你有所帮助&#xff01; 文章目录 一、什么是Docker Registry …

Python Selenium如何下载网页中的图片到本地?(Base64编码的图片下载)

前言&#xff1a; 在网页上&#xff0c;图片有时会以Base64编码的形式嵌入在HTML中&#xff0c;而不是作为单独的文件提供。这种方式的优点是可以减少HTTP请求的数量&#xff0c;因为图片数据直接包含在HTML中&#xff0c;不需要额外的请求来获取图片文件。这对于小图片…

如何解决vscode中文路径的问题

首先我们进入设备 搜索“区域”&#xff0c;选择“区域设置” 点击管理语言设置 点击更改系统区域设置&#xff0c;勾选“Beta 版: 使用 Unicode UTF-8 提供全球语言支持(U)”&#xff0c;电脑会叫你重启&#xff0c;你重启就行了

mysql四大引擎、账号管理以及建库

目录 一.数据库存储引擎1.1存储引擎的查看1.2InnoDB1.3MyISAM1.4 MEMORY1.5 Archive 二.数据库管理2.1元数据库分类2.2 操作2.3 MySQL库 三.数据表管理3.1三大范式3.2 整形3.3 实数3.4 字符串3.5 text&blob3.6 日期类型3.7 选中标识符 四.数据库账号管理4.1 查询用户4.2查看…

某音关键词搜索商品接口,某音关键词搜索商品列表接口,宝贝详情页接口,某音商品比价接口接入方案

要接入API接口以采集电商平台上的商品数据&#xff0c;可以按照以下步骤进行&#xff1a; 1、找到可用的API接口&#xff1a;首先&#xff0c;需要找到支持查询商品信息的API接口。这些信息通常可以在电商平台的官方文档或开发者门户网站上找到。 2、注册并获取API密钥&#x…

DRF从入门到精通九(权限控制)

文章目录 一、权限控制模型1) ACL(Access Control List,访问控制列表)2) RBAC(Role-Based Access Control,基于角色的访问控制)应用前后台权限控制实操 3) ABAC(Attribute-Based Access Control,基于属性的访问控制) 一、权限控制模型 1) ACL(Access Control List,访问控制列表…

dart 学习 区分好setter,getter和一般的函数

看看代码可以很好的分析 setter &#xff0c;getter 和普通的函数有什么区别 void main() {car a new car("奔驰", 12);print(a.name);a.age 100;print(a.age);a.setname "宝马"; // 调用 setterprint(a.getage); // 调用gettera.setter("雷克萨斯…