xv6实验记录(二)

xv6实验记录(二)

  • 实验科目:操作系统原理及项目设计

  • 实验题目:实验平台搭建和几个练手程序

  • 实验时间:2023/9/25

  • 友情链接: 友情链接

一、实验目的:

  1. 了解系统调用

二、实验内容:

  1. 完成trace()的新系统调用
  2. 完成sysinfo()的新系统调用

三、实验内容

(1)trace()系统调用的实现

(1)首先切换分支,保存实验记录,并清除编译记录

git checkout syscall
make clean

根据实验提示,在MakeFile文件中找到UPROGS并添加$U/_trace\打开user目录可以看到存在一个user/trace.c文件,观察该文件的源码:

if (trace(atoi(argv[1])) < 0) {
	fprintf(2, "%s: trace failed\n", argv[0]);
	exit(1);
}

看到这一段代码中存在trace()方法的调用【该方法来自user.h】,trace函数接收一个int 类型的整数,返回值类型也是int,如果执行失败返回值为-1。


(2)在user/user.h中添加函数原型

int trace(int);		//NEW ADD

user/usys.pl中添加trace的入口

entry("trace");		//NEW ADD

syscall.h中添加宏定义

#define SYS_close 21
#define SYS_trace 22 //NEW ADD

(3)在proc结构体(在kernel/proc.h)里面添加一个新变量用来存储跟踪号,然后在fork()的时候把结构体里新增加的变量也给复制过去,这样就达到了传参的目的。新的变量是不需要加锁的,因为只会被自己所在的进程使用,所以放在char name[16]之后

修改kernel/proc.h添加变量存储跟踪号

// Per-process state
struct proc {
  // ...
  // these are private to the process, so p->lock need not be held.
  // ,,
  char name[16];               
  char mask[23];           //NEW ADD
};

打开kernel/sysproc.c添加一个trace函数的具体实现

uint64				//新添加的函数定义
sys_trace(void){
  int n;
  if(argint(0, &n) < 0) {
    return -1;
  }
  struct proc *p = myproc();
  char *mask = p->mask;
  int i = 0;
  while(i < 23 && n > 0){
    if(n % 2){
      mask[i++] = '1';
    }else {
      mask[i++] = '0';
    }
    n >>= 1;
  }
  return 0;
}

打开kernel/proc.c文件修改fork()函数在函数中添加一句 safestrcpy(np->mask, p->mask, sizeof(p->mask));即可

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;

  safestrcpy(np->mask, p->mask, sizeof(p->mask));		//NEW ADD
    
  ......
      

为了将trace打印出来,修改kernel/syscall.c中的syscall()函数

extern uint64 sys_trace(void);		//NEW ADD

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

static char *syscall_names[23] = {"","fork","exit","wait","pipe","read","kill",
                                "exec","fstat","chdir","dup","getpid","sbrk","sleep",
                                "uptime","open","write","mknod","unlink","link","mkdir",
                                "close","trace"};

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

  num = p->trapframe->a7;
  if(num > 0 && num < NELEM(syscalls) && syscalls[num]) {
    p->trapframe->a0 = syscalls[num]();
    if (strlen(p->mask) > 0 && p->mask[num] == '1'){		// NEW ADD
        printf("%d: syscall %s -> %d\n", p->pid, syscall_names[num],p->trapframe->a0); 
    }                                                                    
  } else {
    printf("%d %s: unknown sys call %d\n",
            p->pid, p->name, num);
    p->trapframe->a0 = -1;
  }
}

测试效果

trace 32 grep hello README
trace 2147483647 grep hello README

image-20230925124713029

./grade-lab-syscall trace

image-20230925124857961


(2)sysinfo()系统调用的实现

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

(2)在user/user.h中声明sysinfo() 函数的原型,您需要预先声明struct sysinfo的存在:修改user/user.h需要在user.h里再声明一次struct sysinfo的原因是:在参数列表里的参数是看不见本文件外面定义的struct的。

struct stat;
struct rtcdate;
struct sysinfo;			//New ADD

// system calls
// ...
int sysinfo(struct sysinfo *);			//NEW ADD

(3)在user/usys.pl中添加sysinfo的入口

entry("sysinfo");		//NEW ADD

(4)在syscall.h中添加宏定义

#define SYS_close 21
#define SYS_trace 22
#define SYS_sysinfo 23

(5)修改kernel/syscall.c中的syscall()函数

extern uint64 sys_info(void);
static uint64 (*syscalls[])(void) = {
// ...
[SYS_sysinfo] sys_info,
};

static char* syscall_names[] = {
// ...
  [SYS_sysinfo] "sys_info",
};

(6)编辑sysproc.c文件,先添加函数体

uint64 sys_info(void) {
  return 0;
}

(7)打开sysproc.c文件添加\#include "sysinfo.h"

(8)要获得空闲内存的数目,请向kernel/kalloc.c添加一个函数kfreemem

// get free memory bytes by count freelist
uint64 kfreemem(void) {
  struct run *r;
  uint64 count = 0;acquire(&kmem.lock);
  r = kmem.freelist;
  while (r) {
    r = r->next;
    count++;
  }
  release(&kmem.lock);
  return count * PGSIZE;
}

(9)要获得进程的数量,请在kernel/proc.c中添加一个函数proc_num()

// get the number of processes whose state is not UNUSED
uint64 proc_num() {
  struct proc *p;
  uint64 count = 0;
  for(p = proc; p < &proc[NPROC]; p++) {
    acquire(&p->lock);
    if(p->state != UNUSED) {
      count++;
    }
    release(&p->lock);
  }
  return count;
}

(10)在kernel/defs.h文件中添加函数原型

uint64          proc_num(void);         //NEW ADD
uint64          kfreemem(void);         //NEW ADD

(11)修改kernel/sysproc.c文件的sys_info()的函数体

uint64 sys_info(void) {
  struct sysinfo info;
  uint64 addr;
  info.freemem = kfreemem();
  info.nproc = proc_num();
  if(argaddr(0, &addr) < 0) {
    return -1;
  }
  // copy info(kernel space) to addr(user space)
  if (copyout(myproc()->pagetable, addr, (char *)&info, sizeof(info)) < 0) {
    return -1;
  } else {
    return 0;
  }
}

测试效果

./grade-lab-syscall sysinfo

image-20230925130757238

总测试

  • 在xv6-lab-2021的目录下新建time.txt文件,之后输入一个整数代表你做实验的时间,单位是小时。之后就可以运行make grade来测试自己的成绩。
make grade		//用来测试自己的实验成绩

image-20230925131445543

如果上述测试失败,检查错误原因是否是因为

  1. trace的打印格式有无错误

  2. 机器硬件不行,测试时间长,qemu认为超时【解决方法打开目录下的gradelib.py文件调整timeout时间】

    image-20230925131647952

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_橙留香

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值