6.S081 lab2.2--sysinfo

MIT 6.s081 lab2.2–sysinfo

No.1 写在前面的话

有了trace仔细钻研的基础,sysinfo就显得简单了许多,不过,还是有一些小坑需要避免【我就踩到了】。

No.2 实验思路

在进行每次实验之前都应该仔细读要求。题目提及sysinfo收集有关正在运行的系统的信息,看一看user/sysinfotest.c:

int
main(int argc, char *argv[])
{
  printf("sysinfotest: start\n");
  testcall();
  testmem();
  testproc();
  printf("sysinfotest: OK\n");
  exit(0);
}

养成看一段代码前先看main的习惯,通过这里就可以简单知道,sysinfo会开始测试系统调用,内存和进程情况;简单了解后,代码就可以开始写了:

添加系统调用的步骤在此处略过,首先模仿所写trace,根据题目要求【系统调用采用一个参数:一个指向struct sysinfo的指针】可写得:

uint64
sys_sysinfo(void){
  struct sysinfo info;//指向struct sysinfo的指针

  if(argaddr(0, &) < 0)//因为是指针,利用argaddr
    return -1;
    
  return 0;
}

接下来开始慢慢补充。

提示说,sysinfo需要将一个struct sysinfo复制回用户空间,给出了需要参阅的代码,我们看一看:

//sys_fstat()
uint64
sys_fstat(void)
{
  struct file *f;
  uint64 st; // user pointer to struct stat

  if(argfd(0, 0, &f) < 0 || argaddr(1, &st) < 0)
    return -1;
  return filestat(f, st);
}

//filestat()
// Get metadata about file f.
// addr is a user virtual address, pointing to a struct stat.
int
filestat(struct file *f, uint64 addr)
{
  struct proc *p = myproc();
  struct stat st;
  
  if(f->type == FD_INODE || f->type == FD_DEVICE){
    ilock(f->ip);
    stati(f->ip, &st);
    iunlock(f->ip);
    if(copyout(p->pagetable, addr, (char *)&st, sizeof(st)) < 0)
      return -1;
    return 0;
  }
  return -1;
}

但是实际上有用的信息并不多,它只是告诉我们用户指针的st以及一个用户虚拟地址指向st,另外又进行了文件的判断,这么看并没有思路。但是我们注意到filestat()中的copyout,进行追踪,看到这条消息:

// Copy from kernel to user.
// Copy len bytes from src to virtual address dstva in a given page table.
// Return 0 on success, -1 on error.
//将 len 个字节从 src 复制到给定页表中的虚拟地址 dstva
int
copyout(pagetable_t pagetable, uint64 dstva, char *src, uint64 len)

实际上,注释已经写的很明白,通过理解可得:要将一个struct sysinfo复制回用户空间,可以利用copyout,将sysinfo所占的总字节逐个拷贝到虚拟地址【之后的页表课可以得知,在这里的虚拟地址就是用户空间】,那么根据filestat,模仿可得:

if(copyout(p->pagetable, addr, (char *)&info, sizeof(info)) < 0)
      return -1;

但是这里的addr还很迷糊,应该指向哪里,实际上,通过参看提示中的声明可得:

struct sysinfo;
int sysinfo(struct sysinfo *);

也就是说,用户调用sysinfo后我们会获得一个指针,指向sysinfo的地址;而sysinfo预先被我们声明在user.h中,这就表明,它的地址也就是用户态下的虚拟地址,那么,补充变量,用于存储地址:

  uint64 addr;//其实我并不知道为什么用uint64,只是模仿定义
  if(argaddr(0, &addr) < 0)

这样三分之一就已经完成,继续往下进行。

首先看一看kalloc.c:

// Allocate one 4096-byte page of physical memory.
// Returns a pointer that the kernel can use.
// Returns 0 if the memory cannot be allocated.
void *
kalloc(void)
{
  struct run *r;

  acquire(&kmem.lock);
  r = kmem.freelist;
  if(r)
    kmem.freelist = r->next;
  release(&kmem.lock);

  if(r)
    memset((char*)r, 5, PGSIZE); // fill with junk
    //memset的作用是复制字符5到参数r【也即空闲链表】所指处的前pgsize个字符
    //名副其实的填充垃圾……
    //pgsize——每页字节数
  return (void*)r;
}

那么现在就清楚了,要获取空闲内存量,就可以借助freelist进行,利用int存储遍历的结果,最后返回即可。当然,目前还不清楚锁,也还是模仿得:

//获取空闲内存量
int
GetMem(void)
{
  struct run *r;
  uint64 freebits = 0;

  acquire(&kmem.lock);
  r = kmem.freelist;

  //因为要持续获得,得用while连续判断,一开始我用if
  while(r){
    ++freebits;
    kmem.freelist = r->next;
  }
  release(&kmem.lock);

  return freebits * PGSIZE;
  //一个freelist表示一【页】freemem
  //我一开始没想到,只是返回freebits.
  //但要知道空闲内存【量】,不应该只是知道有几页,还要知道每一页占多大
}

在这里,光是写出来还不够,因为重新添加了一个函数,我们得要和添加系统调用原型一样添加函数定义才行:

//defs.h
// kalloc.c
void*           kalloc(void);
void            kfree(void *);
void            kinit(void);
int             GetMem(void);

继续查看如何获取进程数,来到proc.c,根据题目要求,需要设置一个不为【UNUSED】的数,那么就得寻找使用示例。在这里,我先在最后定义了准备填写的函数,正要寻找怎么获取,没想到上面的procdump()就有我想获取的信息【太好了!】;我们只需看一看这里:

  struct proc *p;
  char *state;

  printf("\n");
  for(p = proc; p < &proc[NPROC]; p++){
    if(p->state == UNUSED)
      continue;

很明显,这段for循环就是在遍历进程,如果是未使用则直接跳过,正好符合要求,模仿可得:

//获取进程数
int
GetProcNum(void){
  struct proc *p;
  uint64 count = 0;

  for(p = proc; p < &proc[NPROC]; p++){
    //目前为止还不知道锁的知识,但是觉得有必要加入
    acquire(&p->lock);
    if(p->state == UNUSED){
      continue; 
    }
    else{ ++count;}
    release(&p->lock);   
  }
  return count;
}

与kalloc类似,也需要填入函数声明,目前为止,代码已经几乎完成。

我们目前只是补充了函数,但并没有对其进行调用;根据要求:【内核应该填写这个结构的字段:freemem字段应该设置为空闲内存的字节数,nproc字段应该设置为state字段不为UNUSED的进程数。】那么现在,是时候补充了! 完整代码如下:

uint64
sys_sysinfo(void){
  uint64 addr;
  struct sysinfo info;//指向struct sysinfo的指针
  struct proc *p = myproc();

  if(argaddr(0, &addr) < 0)//先判断地址是否存在
    return -1;

  info.freemem = GetMem();
  info.nproc = GetProcNum();

  //将一个struct sysinfo复制回用户空间
  if(copyout(p->pagetable, addr, (char *)&info, sizeof(info)) < 0)
      return -1;
  //要先进行赋值才能返回用户空间
  return 0;
}

注意!

最后运行时如果timeout,来到gradelib.py的419行,将timeout时间改久一些,再次运行就可成功。

用时半天。

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值