205.Mit6.S081-实验二 system calls

news2025/1/20 5:42:55

Lab2:system calls

        在上一个实验室中,您使用系统调用编写了一些实用程序。在本实验室中,您将向xv6添加一些新的系统调用,这将帮助您了解它们是如何工作的,并使您了解xv6内核的一些内部结构。您将在以后的实验室中添加更多系统调用。

一、实验准备

在你开始写代码之前,请阅读xv6手册《book-riscv-rev1》的第2章、第4章的第4.3节和第4.4节以及相关源代码文件:

  • 系统调用的用户空间代码在user/user.huser/usys.pl中。
  • 内核空间代码是kernel/syscall.hkernel/syscall.c
  • 与进程相关的代码是kernel/proc.hkernel/proc.c

可看这一篇博客来增加理解。

158.xv6——2(system calls)-CSDN博客

要开始本章实验,请将代码切换到syscall分支:

$ git fetch
$ git checkout syscall
$ make clean

如果运行make grade,您将看到测试分数的脚本无法执行tracesysinfotest。您的工作是添加必要的系统调用和存根(stubs)以使它们工作。

二、System call tracing实验(moderate)

 1.需求

        在本作业中,您将添加一个系统调用跟踪功能,该功能可能会在以后调试实验时对您有所帮助。您将创建一个新的trace系统调用来控制跟踪。它应该有一个参数,这个参数是一个整数“掩码”(mask),它的比特位指定要跟踪的系统调用。例如,要跟踪fork系统调用,程序调用trace(1 << SYS_fork),其中SYS_forkkernel/syscall.h中的系统调用编号。如果在掩码中设置了系统调用的编号,则必须修改xv6内核,以便在每个系统调用即将返回时打印出一行。该行应该包含进程id、系统调用的名称和返回值;您不需要打印系统调用参数。trace系统调用应启用对调用它的进程及其随后派生的任何子进程的跟踪,但不应影响其他进程。

        我们提供了一个用户级程序版本的trace,它运行另一个启用了跟踪的程序(参见user/trace.c)。完成后,您应该看到如下输出:

$ trace 32 grep hello README
3: syscall read -> 1023
3: syscall read -> 966
3: syscall read -> 70
3: syscall read -> 0
$
$ trace 2147483647 grep hello README
4: syscall trace -> 0
4: syscall exec -> 3
4: syscall open -> 3
4: syscall read -> 1023
4: syscall read -> 966
4: syscall read -> 70
4: syscall read -> 0
4: syscall close -> 0
$
$ grep hello README
$
$ trace 2 usertests forkforkfork
usertests starting
test forkforkfork: 407: syscall fork -> 408
408: syscall fork -> 409
409: syscall fork -> 410
410: syscall fork -> 411
409: syscall fork -> 412
410: syscall fork -> 413
409: syscall fork -> 414
411: syscall fork -> 415
...
$

        在上面的第一个例子中,trace调用grep,仅跟踪了read系统调用。321<<SYS_read。在第二个示例中,trace在运行grep时跟踪所有系统调用;2147483647将所有31个低位置为1。在第三个示例中,程序没有被跟踪,因此没有打印跟踪输出。在第四个示例中,在usertests中测试的forkforkfork中所有子孙进程的fork系统调用都被追踪。如果程序的行为如上所示,则解决方案是正确的(尽管进程ID可能不同)

2.提示:

  • MakefileUPROGS中添加$U/_trace
  • 运行make qemu,您将看到编译器无法编译user/trace.c,因为系统调用的用户空间存根还不存在:将系统调用的原型添加到user/user.h,存根添加到user/usys.pl,以及将系统调用编号添加到kernel/syscall.hMakefile调用perl脚本user/usys.pl,它生成实际的系统调用存根user/usys.S,这个文件中的汇编代码使用RISC-V的ecall指令转换到内核。一旦修复了编译问题(注:如果编译还未通过,尝试先make clean,再执行make qemu),就运行trace 32 grep hello README;但由于您还没有在内核中实现系统调用,执行将失败。
  • kernel/sysproc.c中添加一个sys_trace()函数,它通过将参数保存到proc结构体(请参见kernel/proc.h)里的一个新变量中来实现新的系统调用。从用户空间检索系统调用参数的函数在kernel/syscall.c中,您可以在kernel/sysproc.c中看到它们的使用示例。
  • 修改fork()(请参阅kernel/proc.c)将跟踪掩码从父进程复制到子进程。
  • 修改kernel/syscall.c中的syscall()函数以打印跟踪输出。您将需要添加一个系统调用名称数组以建立索引。

3.trace实现

本实验主要是实现一个追踪系统调用的函数,那么首先根据提示定义trace系统调用,并修复编译错误。

首先看一下user/trace.c的内容,主要的代码如下

// 调用 trace 系统调用,并传递第一个命令行参数的整数值
if (trace(atoi(argv[1])) < 0) {
    // 如果 trace 调用失败,打印错误信息并退出
    fprintf(2, "%s: trace failed\n", argv[0]);
    exit(1);
}

// 将命令行参数从 argv[2] 开始复制到 nargv 数组中
for (i = 2; i < argc && i < MAXARG; i++) {
    nargv[i-2] = argv[i];
}

// 使用 exec 系统调用执行 nargv[0] 命令,并传递 nargv 数组作为参数
exec(nargv[0], nargv);

它首先调用trace(int),然后将命令行中的参数argv复制到nargv中,同时删去前两个参数,例如

argv  = trace 32 grep hello README
nargv = grep hello README

那么,根据提示,我们首先再proc结构体中添加一个数据字段,用于保存trace的参数。并在sys_trace()的实现中实现参数的保存

// kernel/proc.h
struct proc {
  // ...
  int trace_mask;    // trace系统调用参数
};

// kernel/sysproc.c
uint64
sys_trace(void)
{
  // 获取系统调用的参数
  argint(0, &(myproc()->trace_mask));
  return 0;
}

由于struct proc中增加了一个新的变量,当fork的时候我们也需要将这个变量传递到子进程中(提示中已说明)

//kernel/proc.c
int
fork(void)
{
  // ...

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

  //将trace_mask拷贝到子进程
  np->trace_mask = p->trace_mask;

  pid = np->pid;
  // ...

  return pid;
}

接下来应当考虑如何进行系统调用追踪了,根据提示,这将在syscall()函数中实现。下面是实现代码,需要注意的是条件判断中使用了&而不是==,这是因为在实验说明书的例子中,trace 2147483647 grep hello README将所有31个低位置为1,使得其可以追踪所有的系统调用。

void
syscall(void)
{
  int num;
  struct proc *p = myproc();

  num = p->trapframe->a7;  // 系统调用编号,参见书中4.3节
  if(num > 0 && num < NELEM(syscalls) && syscalls[num]) {
    p->trapframe->a0 = syscalls[num]();  // 执行系统调用,然后将返回值存入a0

    // 系统调用是否匹配
    if ((1 << num) & p->trace_mask)
      printf("%d: syscall %s -> %d\n", p->pid, syscalls_name[num], p->trapframe->a0);
  } else {
    printf("%d %s: unknown sys call %d\n",
            p->pid, p->name, num);
    p->trapframe->a0 = -1;
  }
}

在上面的代码中,我们还有一些引用的变量尚未定义,在syscall.c中定义他们

// ...
extern uint64 sys_trace(void);

static uint64 (*syscalls[])(void) = {
// ...
[SYS_trace]   sys_trace,
};

static char *syscalls_name[] = {
[SYS_fork]    "fork",
[SYS_exit]    "exit",
[SYS_wait]    "wait",
[SYS_pipe]    "pipe",
[SYS_read]    "read",
[SYS_kill]    "kill",
[SYS_exec]    "exec",
[SYS_fstat]   "fstat",
[SYS_chdir]   "chdir",
[SYS_dup]     "dup",
[SYS_getpid]  "getpid",
[SYS_sbrk]    "sbrk",
[SYS_sleep]   "sleep",
[SYS_uptime]  "uptime",
[SYS_open]    "open",
[SYS_write]   "write",
[SYS_mknod]   "mknod",
[SYS_unlink]  "unlink",
[SYS_link]    "link",
[SYS_mkdir]   "mkdir",
[SYS_close]   "close",
[SYS_trace]   "trace",
};

4.测试结果

在xv6-labs-2020中,执行下面指令,测试程序

./grade-lab-syscall trace

将你当前的修改提交到你的版本控制系统中,以保存当前工作的进度。

git commit -m "实现并通过了 trace 系统调用的所有测试"

三、System call sysinfo

1.实验要求

        在这个作业中,您将添加一个系统调用sysinfo,它收集有关正在运行的系统的信息。系统调用采用一个参数:一个指向struct sysinfo的指针(参见kernel/sysinfo.h)。内核应该填写这个结构的字段:freemem字段应该设置为空闲内存的字节数,nproc字段应该设置为state字段不为UNUSED的进程数。我们提供了一个测试程序sysinfotest;如果输出“sysinfotest: OK”则通过。

2.提示

  • MakefileUPROGS中添加$U/_sysinfotest
  • 当运行make qemu时,user/sysinfotest.c将会编译失败,遵循和上一个作业一样的步骤添加sysinfo系统调用。要在user/user.h中声明sysinfo()的原型,需要预先声明struct sysinfo的存在:

3.sysinfo实现

(1)在Makefile的UPROGS中添加$U/_sysinfotest

(2)在kernel/syscall.h中添加宏定义

#define SYS_sysinfo  23

(3)在user/usys.pl中添加entry("sys_info")

(4)在user/user.h中新增sysinfo结构体和sysinfo函数声明

(5)在kernel/syscall.c中添加sysinfo函数定义

(6)在kernel/syscall.c中添加sysinfo数组以及syscall_names中添加

(7)在kernel/kalloc.c中添加一个函数用于获取空闲内存量

uint64
getfreemem(void)
{
  struct run *r;
  uint64 ret = 0;
  acquire(&kmem.lock);
  r = kmem.freelist;
  while(r)
  {
    ret += PGSIZE;
    r = r->next;
  }
  release(&kmem.lock);
  return ret;
}

(8)在kernel/proc.c中添加一个函数获取进程数

遍历proc数组,统计处于活动状态的进程即可,循环的写法参考scheduler函数

uint64
getnproc(void)
{
  struct proc *p;
  uint64 ret = 0;
  for (p = proc; p < &proc[NPROC];p++)
  {
    if(p->state!=UNUSED)
    {
      ret++;
    }
  }
  return ret;
}

(9)实现sys_sysinfo,将数据写入结构体并传递到用户空间

uint64 sys_sysinfo(void)
{
  uint64 addr;
  if(argaddr(0,&addr)<0)
  {
    return -1;
  }

  struct sysinfo si;
  struct proc *p = myproc();
  si.freemem = getfreemem();
  si.nproc = getnproc();
  
  if(copyout(p->pagetable,addr,(char*)&si,sizeof(si))<0)
  {
    return -1;
  }

  return 0;
}

4.测试结果

在xv6-labs-2020中,执行下面指令,测试程序

./grade-lab-syscall sysinfo

将代码先保存在本地

推送到远程仓库

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

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

相关文章

人工智能期末复习笔记(更新中)

分类问题 分类&#xff1a;根据已知样本的某些特征&#xff0c;判断一个新的样本属于哪种已知的样本类 垃圾分类、图像分类 怎么解决分类问题 分类和回归的区别 1. 逻辑回归分类 用于解决分类问题的一种模型。根据数据特征或属性&#xff0c;计算其归属于某一类别 的概率P,…

[Cloud Networking] OSPF

OSPF 开放式最短路径优先&#xff08;Open Shortest Path First&#xff09;是一种动态路由协议&#xff0c;它属于链路状态路由协议&#xff0c;具有路由变化收敛速度快、无路由环路、支持变长子网掩码和汇总、层次区域划分等优点。 1 OSPF Area 为了适应大型网络&#xff0…

C程序设计谭浩强第五版

程序习题 第一章1、第5题2、第6题 第三章1、第2题2、第2题3、第3题4、第4题Tips 第一章 1、第5题 编写一个C程序,运行时输出以下图形: #include <stdio.h> int main() {for (int i 0; i < 4; i) // 输出4行循环控制{for (int j 0; j < i; j) //第几行就输出几…

leetcode-19-回溯-组合问题(剪枝、去重)

引自代码随想录 一、[77]组合 给定两个整数 n 和 k&#xff0c;返回 1 ... n 中所有可能的 k 个数的组合。 示例: 输入: n 4, k 2 输出: [ [2,4], [3,4], [2,3], [1,2], [1,3], [1,4]] 1、大致逻辑 k为树的深度&#xff0c;到叶子节点的路径即为一个结果 开始索引保证不…

一、Redis简介

一、Redis介绍与一般应用 1.1 基本了解 Redis全称Remote Dictionary Server(远程字典服务)&#xff0c; 是一个开源的高性能键值存储系统&#xff0c;通常用作数据库、缓存和消息代理。使用ANSI C语言编写遵守BSD协议&#xff0c;是一个高性能的Key-Value数据库提供了丰富的数…

VMware中的三种虚拟网络模式

虚拟机网络模式 1 主机网络环境2 VMware中的三种虚拟网络模式2.1 桥接模式2.2 NAT模式2.3 仅主机模式 3 网络模式选择及配置NAT模式3.1 VMware虚拟网络配置3.2 虚拟机选择网络模式3.3 Windows主机网络配置 4 配置静态IP 虚拟机联网方式为桥接模式&#xff0c;这种模式下&#x…

5.6 0-1背包问题

#include<iostream> #include<string> #include<stdlib.h> #include<bits/stdc.h> using namespace std;int c;//背包容纳的重量 int n;//物品数量 int cw;//当前重量 int cv;//当前价值 int bestv;//当前最优价值 int x[100]; int bestx[100]; struct…

Python 算法交易实验75 QTV200后续想法梳理

说明 在第一步获取数据源&#xff0c;然后进入Mongo(第一个数据节点)开始&#xff0c;QTV200的数据流体系就开始动了。后续用多少时间完成不太好确定&#xff0c;短则数周&#xff0c;长则数月。毕竟有过第一版实验的基础&#xff0c;应该还是可以做到的。 下面就是天马行空&…

【TB作品】玩具电子琴,ATMEGA128单片机,Proteus仿真

题目 7 &#xff1a;玩具电子琴 基于单片机设计一能够发出中音八个音阶的音乐信号的电子琴&#xff0c;能够实现弹奏和音符显示功 能。 具有 8 个音阶按键&#xff0c;每按下一个按键时&#xff0c;所对应的 LED 点亮&#xff0c;音符进行显示。 具体要求如下&#xff1a; &…

zabbix server client 安装配置

Zabbix Server 采用源码包部署&#xff0c;数据库采用 MySQL8.0 版本&#xff0c;zabbix-web 使用 nginxphp 来实现。具体信息如下&#xff1a; 软件名 版本 安装方式 Zabbix Server 6.0.3 源码安装 Zabbix Agent 6.0.3 源码安装 MySQL 8.0.28 yum安装 Nginx 1.20…

淀山湖之行随笔

我们仰望清新&#xff0c;但又不得不被世俗所伴。 近日上海开始进入梅雨季节&#xff0c;每天大大小小的雨水不断&#xff0c;整个环境也格外的潮湿&#xff0c;不过已经逐渐习惯这种气候&#xff0c;所谓的见怪不怪。 今日是周日&#xff0c;思绪好久&#xff0c;准备去淀山湖…

贪心问题(POJ1700/1017/1065)(C++)

一、贪心问题 贪心算法 贪心算法&#xff08;greedy algorithm&#xff09;&#xff0c;是用计算机来模拟一个「贪心」的人做出决策的过程。这个人十分贪婪&#xff0c;每一步行动总是按某种指标选取最优的操作。而且他目光短浅&#xff0c;总是只看眼前&#xff0c;并不考虑…

【mysql死锁】示例 和讨论 “SHOW ENGINE INNODB STATUS“

文章目录 mysql 死锁死锁演示表结构如下 死锁查询mysql 详情命令行 SHOW ENGINE INNODB STATUS 如果 两个事务都是按照先更新1 再更新2的顺序去做更新 会发生死锁么&#xff1f;验证一下所以 如果顺序是一致的 不会产生死锁 只会进行等待 防止mysql 死锁的方式优化sql 自行顺序…

(2024,DDPM,DDIM,流匹配,SDE,ODE)扩散:基础教程

Step-by-Step Diffusion: An Elementary Tutorial 公和众与号&#xff1a;EDPJ&#xff08;进 Q 交流群&#xff1a;922230617 或加 VX&#xff1a;CV_EDPJ 进 V 交流群&#xff09; 目录 0 前言 1 扩散的基础知识 1.1 高斯扩散 1.2 抽象中的扩散 1.3 离散化 2 随机采样…

React 打包时如何关闭源代码混淆

React 开发中&#xff0c;使用 npm build 命令进行生产代码打包&#xff0c;为了压缩代码并尽量保证代码的安全性&#xff0c;React 打包时会代码进行压缩和混淆&#xff0c;但是有时我们需要 debug 生产环境的源代码&#xff0c;例如当我们调试 SSR 的项目时&#xff0c;需要禁…

业务模型扩展字段存储

构建业务模型时&#xff0c;通常模型会设置扩展信息&#xff0c;存储上一般使用JSON格式存储到db中。JSON虽然有较好的扩展性&#xff0c;但并没有结构化存储的类型和非空等约束&#xff0c;且强依赖代码中写入/读取时进行序列化/反序列化操作&#xff0c; 当扩展信息结构简单且…

SpringMVC(1)——入门程序+流程分析

MVC都是哪三层&#xff1f;在Spring里面分别对应什么&#xff1f;SpringMVC的架构是什么&#xff1f; 我们使用Spring开发JavaWeb项目&#xff0c;一般都是BS架构&#xff0c;也就是Browser&#xff08;浏览器&#xff09;-Server&#xff08;服务器&#xff09;架构 这种架构…

JVM(12):虚拟机性能分析和故障解决工具之JConsole

1 JConsole作用 查看Java应用程序的运行概况&#xff0c;监视垃圾收集器管理的虚拟机内存(堆和元空间)的变化趋势&#xff0c;以及监控程序内的线程。 2 使用说明 代码如下&#xff1a; package com.example.demo;import java.io.IOException; import java.util.ArrayList; …

AliyunOS安装Node.js

方法1&#xff1a;dnf软件包安装工具自动安装 最方便的安装方式是通过系统的dnf工具&#xff0c;我测试使用的AliyunOS的版本是Alibaba Cloud Linux 3.2104&#xff0c;具体流程如下&#xff1a; dnf module list nodejs #列出服务器中可以使用的所有nodejs版本确定下来希望安…

[Ant Design Vue 树控件Tree]内存溢出报错

使用ant design vue控件时发现报错&#xff0c;但是数据展示时没有问题的&#xff1b; 具体报错信息&#xff1a;Maximum call stack size exceeded 经排查&#xff0c;是我的目录下数据过多&#xff0c;差不多有小一万的数据&#xff1b; 查看官方文档&#xff0c;使用虚拟滚…