MIT6.828实验:Xv6 and Unix utilities

2023MIT6.828 lab-1

官方地址

一、sleep

实验内容

  • 调用sleep(系统调用)编写用户级别程序
  • 能暂停特定时常的系统滴答
  • 程序保存在user/sleep.c

实验过程

xv6的参数传递

查看官方文档提示的文件中,多采用如下定义:

int main(int argc, char *argv[])
在xv6操作系统中:
1、argc 是一个常见的参数,用于表示传递给程序的命令行参数的数量。 
2、argv(argument vector)是一个指向字符指针数组的指针,该数组中的每个元素都是一个指向命令行参数的字符串的指针。
3、程序的内部可通过argc和argv来访问外界输入的参数
注意:
1、argc指示出程序执行时传入的参数个数,常可用来判断输入是否符合要求
2、argv[]为存放字符指针的数组,我们需要的是其指向地址存放的数据,若要当整型数据使用还需进行相应转换

实现代码

#include "kernel/types.h"     //调用相应的头文件
#include "kernel/stat.h"
#include "user/user.h"
int main( int argc ,char *argv[])  //通过argc和argv传入参数
{
	if(argc!=2)   //传入参数数量不符合
	{
	  fprintf(2,"usage:sleep time\n");
	  exit(1);
	}
sleep(atoi(argv[1]));  //由于argc[]指向字符型数据,调用atoi()进行转换
fprintf(2,"nothing happens for a little while\n");
exit(0);  //退出程序
}

编译准备

在make qemu之前,还需进行将编写的sleep()程序加入编译文件中:

1、进入lab目录下
vi Makefile  //打开文件
: ?UPROGS   //vim下搜索关键词

2、定位到UPROGS,在最后一处按格式补入sleep():
UPROGS=\
        $U/_cat\
        $U/_echo\
        $U/_forktest\
        $U/_grep\
        $U/_init\
        $U/_kill\
        $U/_ln\
        $U/_ls\
        $U/_mkdir\
        $U/_rm\
        $U/_sh\
        $U/_stressfs\
        $U/_usertests\
        $U/_grind\
        $U/_wc\
        $U/_zombie\
        $U/_sleep\

3、保存退出

编译运行

make qemu

xv6 kernel is booting
hart 1 starting
hart 2 starting
init: starting sh
$ sleep 10
nothing happens for a little while  //停顿后显示,达到实验效果

工具测试

在lab目录下执行:
$ ./grade-lab-util sleep
或
$ make GRADEFLAGS=sleep grade

输出:
在这里插入图片描述
测试通过

二、pingpong

实验内容

  • 在父进程中创建子进程
  • 编写用户级程序调用系统调用通过一对pipes在两个进程间实现’‘ping-pong’’ 一个字节
  • 父进程给子进程发送一字节,子进程收到后print “: received ping” 这里的 is its process ID,并通过pipes给父进程传递一字节,然后exit
  • 父进程读取来自子进程的字节,并print “: received pong”,然后exit
  • 程序保存在user/pingpong.c

实验过程

fork用法

打开/kernel/proc.c查看fork()源码

// Create a new process, copying the parent.
// Sets up child kernel stack to return as if from fork() system call.
int
fork(void)
{
  int i, pid;
  struct proc *np;
  struct proc *p = myproc();

  // Allocate process.
  if((np = allocproc()) == 0){
    return -1;
  }

  // Copy user memory from parent to child.
  if(uvmcopy(p->pagetable, np->pagetable, p->sz) < 0){
    freeproc(np);
    release(&np->lock);
    return -1;
  }
  np->sz = p->sz;

  // copy saved user registers.
  *(np->trapframe) = *(p->trapframe);

  // Cause fork to return 0 in the child.
  np->trapframe->a0 = 0;

  // increment reference counts on open file descriptors.
  for(i = 0; i < NOFILE; i++)
    if(p->ofile[i])
      np->ofile[i] = filedup(p->ofile[i]);
  np->cwd = idup(p->cwd);

  safestrcpy(np->name, p->name, sizeof(p->name));

  pid = np->pid;

  release(&np->lock);

  acquire(&wait_lock);
  np->parent = p;
  release(&wait_lock);

  acquire(&np->lock);
  np->state = RUNNABLE;
  release(&np->lock);

  return pid;
}
该函数的作用:
1、创建一个新进程,并复制父进程的内容
2、为子进程(child process)设置内核栈(kernel stack),以便在子进程执行完毕后,其行为表现得就像是从 fork() 系统调用返回一样
3、父子进程内容相同(除个别数据),但内存空间不同,修改互不影响
4、在父进程中,fork()返回新创建的子进程的进程ID;在子进程中,fork()返回0;如果发生错误,则返回-1

结构体proc的声明
该结构体存储了每一个进程的信息

// Per-process state
struct proc {
  struct spinlock lock;

  // p->lock must be held when using these:
  enum procstate state;        // Process state
  void *chan;                  // If non-zero, sleeping on chan
  int killed;                  // If non-zero, have been killed
  int xstate;                  // Exit status to be returned to parent's wait
  int pid;                     // Process ID

  // wait_lock must be held when using this:
  struct proc *parent;         // Parent process

  // these are private to the process, so p->lock need not be held.
  uint64 kstack;               // Virtual address of kernel stack
  uint64 sz;                   // Size of process memory (bytes)
  pagetable_t pagetable;       // User page table
  struct trapframe *trapframe; // data page for trampoline.S
  struct context context;      // swtch() here to run process
  struct file *ofile[NOFILE];  // Open files
  struct inode *cwd;           // Current directory
  char name[16];               // Process name (debugging)
};

pipes用法

pipe()函数定义

int pipe(int p[])  Create a pipe, put read/write file descriptors in p[0] and p[1]. 
1、调用pipe函数来创建一个新的管道。如果成功,pipe函数返回0,并将两个文件描述符分别存放在p[0]和p[1]中。如果失败,返回-1。
2、pipe为半双工通信,要根据实际指定通信方向,关闭管道的读或写,保留另一功能
3、可采用两条pipe实现互通

在这里插入图片描述

getpid用法

获取当前进程PID
int getpid()  Return the current process’s PID. 

实现代码

注意:读写顺序
#include "kernel/types.h"
#include "user/user.h"

int main(int argc,int *argv[])
{
  int ptc_pipe[2];
  int ctp_pipe[2];

  pipe(ptc_pipe); //父to子
  pipe(ctp_pipe);//子to父

  int pid;
  pid = fork(); //新建子进程

  if(pid==0) //处于子进程
  {
     //设定管道通信方向
     close(ptc_pipe[1]); //子读取
     close(ctp_pipe[0]); //子写入

     char buff[16];
     if( read( ptc_pipe[0],buff,1) ==1 ) //子进程收到父进程的一字节
     {
        printf("%d: received ping\n",getpid() );
     }

     write( ctp_pipe[1],"p",1 ); //往父进程发送一字节
     exit(0);
  }
  else //处于父进程
  {
        //设置管道方向
        close( ptc_pipe[0] );// 父写入
        close( ctp_pipe[1] );// 父读取

        write( ptc_pipe[1],"p",1 ); //往子进程发送一字节

        char buff[16];
        if( read( ctp_pipe[0],buff,1)==1 )//父进程读取到一字节
        {
          printf("%d: received pong\n",getpid() );
        }
  }
exit(0);
}

编译准备

往Makefile中UPROGS=\项目添加  $U/_pingpong\

运行结果

在这里插入图片描述

工具测试

make GRADEFLAGS=pingpong grade

在这里插入图片描述
测试通过

三、primes

实验内容

1、在xv6中使用pipe编写一个并发的素数筛选程序
2、使用pipe和fork来建立管道
3、第一个进程向管道内输入数字2到35
4、对于每个素数,创建一个进程来从管道左侧读取,并传输给另一条管道右侧
5、受限于xv6的有限文件描述符和进程,第一个进程将在35处停止
6、程序位于user/primes.c

实验过程

过程分析

1、采用pipe进行数字传递,用fork创建下一级,直到结束
2、每级中挑选出一个素数,把剩余经过此素数处理过的传递到下一级
3、传递后父进程要执行等待子进程结束的操作

实现代码

注意:
1、仔细关闭程序不需要的文件描述符,否则在35前xv6的资源会耗尽
2、pipe用完关闭,避免拥塞
3、注意pipe和fork执行顺序
#include "kernel/types.h"
#include "user/user.h"

int children( int ptc_pipe[])
{
  //设置管道方向
  close( ptc_pipe[1] );//子读取,不需要写入

  //对父到子管道进行检查
  int num;
  if( read( ptc_pipe[0] ,&num,sizeof(num)) == 0 ) //管道空
  {
         close( ptc_pipe[0]);
          exit(0);
  }
  else
  {
    printf("prime %d\n",num); //打印素数
  }
  
  //创建孙进程
  int pid;
  int ctg_pipe[2];
  pipe( ctg_pipe );//子进程到孙进程管道

  pid=fork();
  if( pid==0 ) //孙子进程
  {
    children( ctg_pipe );  //递推

  }
  else  //子进程
  {
     //设置子到孙管道方向
     close( ctg_pipe[0] );//子写孙读
     int i;
     while( read( ptc_pipe[0],&i,sizeof(i))>0 ) //管道还有数据
     {
       if( i % num !=0 )//有余数
       write( ctg_pipe[1],&i,sizeof(i) );//发送到下一级
     }
     close( ctg_pipe[1]);//关闭写,避免读拥塞
     wait(0); //等待孙进程结束

  }
  exit(0);//结束返回

}
int main(int argc,int *argv[])
{
    int ptc_pipe[2];
        //建立第一个管道
    pipe(ptc_pipe);

    int pid;
    pid =fork(); //创建子进程

    if( pid==0 ) //位于子进程
    {
       children(ptc_pipe); //函数反复调用
    }
    else //位于父进程
    {
       //管道设置
       close(ptc_pipe[0]); //父写入,不需要读取

       for(int i=2;i<=35;i++) //往管道输入数字
       {
        write(ptc_pipe[1],&i,sizeof(i));
       }
       close( ptc_pipe[1]);//关闭写,避免读拥塞
       wait(0);//等待子进程
    }
exit(0);
}

编译准备

往Makefile中UPROGS=\项目添加  $U/_primes\

运行结果

在这里插入图片描述

工具测试

 make GRADEFLAGS=primes grade

在这里插入图片描述
测试通过

find

实验内容

实验过程

工具测试

更新中

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

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

相关文章

代码随想录算法训练营第三十天| 332.重新安排行程, 51. N皇后, 37. 解数独,总结

题目与题解 参考资料&#xff1a;回溯总结 332.重新安排行程 题目链接&#xff1a;332.重新安排行程 代码随想录题解&#xff1a;332.重新安排行程 视频讲解&#xff1a;带你学透回溯算法&#xff08;理论篇&#xff09;| 回溯法精讲&#xff01;_哔哩哔哩_bilibili 解题思路&a…

【随笔】Git 高级篇 -- 相对引用2(十三)

&#x1f48c; 所属专栏&#xff1a;【Git】 &#x1f600; 作  者&#xff1a;我是夜阑的狗&#x1f436; &#x1f680; 个人简介&#xff1a;一个正在努力学技术的CV工程师&#xff0c;专注基础和实战分享 &#xff0c;欢迎咨询&#xff01; &#x1f496; 欢迎大…

每日一题(leetcode287):寻找重复数--二分查找+思维

思路&#xff1a;看官方解答 class Solution { public:int findDuplicate(vector<int>& nums) {int nnums.size();int left1;int rightn-1;int ans-1;while(left<right){int mid(leftright)/2;int count0;for(int j0;j<n;j){if(nums[j]<mid){count;}}if(co…

小林coding图解计算机网络|基础篇03|Linux 系统是如何收发网络包的?

小林coding网站通道&#xff1a;入口 本篇文章摘抄应付面试的重点内容&#xff0c;详细内容还请移步&#xff1a;小林coding网站通道 文章目录 网络模型Linux 网络协议栈Linux 接收网络包的流程Linux发送网络包的流程为什么全部数据包只用一个结构体来描述呢发送网络数据的时候…

[HackMyVM]靶场Logan2

难度:Medium kali:192.168.56.104 靶机:192.168.56.146 端口扫描 ┌──(root㉿kali2)-[~/Desktop] └─# nmap 192.168.56.146 Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-04-04 19:41 CST Nmap scan report for 192.168.56.146 Host is up (0.000067s latency)…

0201基础集成与使用-微信支付-支付模块-项目实战

文章目录 一、前言二、springboot集成2.1 配置信息与配置类2.2 微信相关枚举信息2.3 工具类2.4 业务接口 三、演示-支付与退款结语 一、前言 下面我以微信支付v3为例&#xff0c;通过spirngboot集成到我们的项目中&#xff0c;不依赖其他第三方框架。当然适用简单项目&#xf…

软考--软件设计师(软件工程总结2)

目录 1.测试方法 2.软件项目管理 3.软件容错技术 4.软件复杂性度量 5.结构化分析方法&#xff08;一种面向数据流的开发方法&#xff09; 6.数据流图 1.测试方法 软件测试&#xff1a;静态测试&#xff08;被测程序采用人工检测&#xff0c;计算机辅助静态分析的手段&…

Unity开发之音效相关

目录 音频文件的导入 音频源相关 麦克风输入相关 获取麦克风设备信息 开始录制 获取音频数据用于存储或者传输 代码控制音频源 动态控制音效播放 示例 音频文件的导入 常用格式&#xff1a;wav,mp3,ogg,aiff Force To Mono(多声道转单声道)Normalize(强制为单声道&am…

C++入门 (2) >>引用>>内联函数>>auto关键字

1 引用 定义&#xff1a;给变量起别名。 方法&#xff1a;在类型后面加上&符号。 主要作用&#xff1a;代替函数传指针。 例&#xff1a; void test(int& a) //参数为int&类型 {a 10; }int main() {int m 3;int& z m; //给m起别名叫z&#xff0…

基于springboot+vue+Mysql的在线考试系统

开发语言&#xff1a;Java框架&#xff1a;springbootJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#xff1a;…

MySQL8,体验不一样的安装方式!

MySQL官网中下载YUM源rpm安装包。 1、把上面的rpm文件下载下来放到服务器上 #或者在linux系统中通过wget命令下载 wget http://dev.mysql.com/get/mysql80-community-release-el7-1.noarch.rpm2、下载完成后使用yum命令本地安装yum源 yum localinstall mysql80-community-rel…

Linux云计算之Linux基础3——Linux基本认识操作

1、终端 终端(terminal)&#xff1a;人和系统交互的必要设备&#xff0c;人机交互最后一个界面&#xff08;包含独立的输入输出设备&#xff09; 物理终端(console)&#xff1a;直接接入本机器的键盘设备和显示器虚拟终端(tty)&#xff1a;通过软件方式虚拟实现的终端。它可以…

IP-guard WebServer 任意文件读取漏洞复现

0x01 产品简介 IP-guard是由溢信科技股份有限公司开发的一款终端安全管理软件,旨在帮助企业保护终端设备安全、数据安全、管理网络使用和简化IT系统管理。 0x02 漏洞概述 由于IP-guard WebServer /ipg/static/appr/lib/flexpaper/php/view.php接口处未对用户输入的数据进行严…

VMamba: Visual State Space Model

VMamba: Visual State Space Model VMamba&#xff1a;视觉状态空间模型 论文链接&#xff1a;http://arxiv.org/abs/2401.10166 代码链接&#xff1a;https://github.com/MzeroMiko/VMamba 1、摘要 借鉴了最近引入的状态空间模型SSM&#xff0c;提出了Visual State Space M…

如何保证Redis的缓存和数据库中的数据的一致性?

Redis的缓存如何和数据库中的数据保持一致性&#xff1f; 我们都知道&#xff0c;Redis是一个基于内存的键值存储系统&#xff0c;数据完全存放在内存中&#xff0c;这使得它的读写速度远超传统的硬盘存储数据库。对于高访问频率、低修改率的数据&#xff0c;通过将它们缓存在…

动态规划:线性dp

1.最长公共子序列(LCS) dp[i][j]含义&#xff1a;序列Ai(a1-ai)和Bj(b1-bj)的最长公共子序列长度 分析两种情况&#xff1a; &#xff08;1&#xff09;当ai bj时&#xff0c;已经求得Ai-1和Bj-1的最长公共子序列 dp[i][j] dp[i-1][j-1] 1 &#xff08;2&#xff09;当…

C++:比较运算符(18)

就是进行数据的比较&#xff0c;表达式正确的话就是真&#xff0c;错的话就是假&#xff0c;真假则由bool值来代替&#xff0c;非0即真 等于&#xff08;为赋值&#xff0c;为比较&#xff09;10 200!不等于10 ! 201>大于10 > 200<小于10 < 201>大于等于20 >…

windows安装Openssl

openssl官网:[ Downloads ] - /source/index.html Windows 安装方法 OpenSSL 官网没有提供 Windows 版本的安装包&#xff0c;可以选择其他开源平台提供的工具 Win32/Win64 OpenSSL Installer for Windows - Shining Light Productions 等待下载完成 捐不起 配置环境变量 ope…

【图论】【基环内向树】【广度优先】【深度优先】2127. 参加会议的最多员工数

作者推荐 视频算法专题 本文涉及知识点 图论 基环内向树 LeetCode2127. 参加会议的最多员工数 一个公司准备组织一场会议&#xff0c;邀请名单上有 n 位员工。公司准备了一张 圆形 的桌子&#xff0c;可以坐下 任意数目 的员工。 员工编号为 0 到 n - 1 。每位员工都有一位…

XML --java学习笔记

XML(全称EXtensible Markup Language&#xff0c;可扩展标记语言) 本质是一种数据的格式&#xff0c;可以用来存储复杂的数据结构&#xff0c;和数据关系 XML的特点 XML中的“<标签名>”称为一个标签或一个元素&#xff0c;一般是成对出现的XML中的标签名可以自己定义…