MIT 6.S081 Lab2:system calls

MIT 6.S081 Lab2 分为以下两个部分

  • System call tracing
  • Sysinfo

System call tracing

这个作业中,我们需要添加一个系统调用追踪功能
看一下给的示例1:

$ trace 32 grep hello README
3: syscall read -> 1023
3: syscall read -> 966
3: syscall read -> 70
3: syscall read -> 0

这个示例中,trace调用grep,仅仅跟踪了read系统调用,32是1<<SYS_read,SYS_read是系统调用编号,在kernel/syscall.h中给出了声明:

// System call numbers
#define SYS_fork    1
#define SYS_exit    2
#define SYS_wait    3
#define SYS_pipe    4
#define SYS_read    5
...

根据比特位如果是1就跟踪指定的系统调用,例如上一个例子中32=(100000),只跟踪read系统调用,如果trace参数为(1111111),那么上面给出的系统调用将会被全部追踪

我们根据给的Hints一步步来看:

首先在Makefile中的UPROGS中添加$U/_trace
将系统调用的原型添加到user/user.h

// system calls
int fork(void);
int exit(int) __attribute__((noreturn));
int wait(int*);
int pipe(int*);
int write(int, const void*, int);
...
int trace(int);

存根添加到user/usys.pl

entry("fork");
entry("exit");
entry("wait");
entry("pipe");
entry("read");
...
entry("trace");

将系统调用编号添加到kernel/syscall.h

// System call numbers
#define SYS_trace  22

完成这些之后,我们执行make qemu,编译正确,接下来我们需要实现trace这个系统调用

在kernel/sysproc.c中添加一个sys_trace()函数,它通过将参数保存到proc结构体(请参见kernel/proc.h)里的一个新变量中来实现新的系统调用,从用户空间检索系统调用参数的函数在kernel/syscall.c中,您可以在kernel/sysproc.c中看到它们的使用示例

修改kernel/syscall.c中的syscall()函数以打印跟踪输出。您将需要添加一个系统调用名称数组以建立索引

通过这两点,我们可以知道,我们最后需要实现的打印输出在syscall函数中,梳理一下流程,我们在sysproc.c中实现的sys_trace函数接收一个mask掩码,保存到proc这个进程结构体中,syscall函数从proc结构体中拿到掩码,再打印输出

首先在proc结构体中添加变量:

uint64 trace_mask;

实现sys_trace函数,将mask保存到proc

uint64 
sys_trace(void){
  int mask;
  if(argint(0, &mask) < 0)
    return -1;
  struct proc *p=myproc();
  p->trace_mask=mask;
  return 0;
}

最后,实现syscall函数,添加一个系统调用名称数组以建立索引,注意num从1开始,我们添加的数组也要从1开始

static char* syscall_nums[]={
  "null","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]();
    int trace_mask=p->trace_mask;
    if((trace_mask>>num)&1){
      printf("%d: syscall %s -> %d\n",p->pid,syscall_nums[num],p->trapframe->a0);
    }
  } else {
    printf("%d %s: unknown sys call %d\n",
            p->pid, p->name, num);
    p->trapframe->a0 = -1;
  }
}

现在我们执行make qemu,执行示例成功

$ trace 32 grep hello README
3: syscall read -> 1023
3: syscall read -> 966
3: syscall read -> 70
3: syscall read -> 0

但是,我们发现不调用trace也会打印输出,但是我们发现这个输出和上面示例输出一致,意味着在这个命令中,mask值可能是上一次遗留的

$ grep hello README
4: syscall read -> 1023
4: syscall read -> 966
4: syscall read -> 70
4: syscall read -> 0

原因是,我们需要在proc.c中的freeproc函数中,添加上p->trace_mask=0;,在每次释放freeproc时候,将mask值清空

修改fork()(请参阅kernel/proc.c)将跟踪掩码从父进程复制到子进程。

// copy trace_mask in the child
np->trace_mask=p->trace_mask;

至此,运行测试用例,PASS

Sysinfo

本作业中,我们需要添加一个系统调用sysinfo,它收集有关正在运行的系统的信息,看一下头文件中的结构体,freemem记录空闲内存的字节数,nproc记录state字段不为UNUSED的进程数

struct sysinfo {
  uint64 freemem;   // amount of free memory (bytes)
  uint64 nproc;     // number of process
};

还是根据Hints一步步来,仿照上一个作业,修复编译问题,不做赘述

sysinfo需要将一个struct sysinfo复制回用户空间;请参阅sys_fstat()(kernel/sysfile.c)和filestat()(kernel/file.c)以获取如何使用copyout()执行此操作的示例

参照sysfile.c中sys_fstat函数中下面这段代码

uint64 st; // user pointer to struct stat
if(argfd(0, 0, &f) < 0 || argaddr(1, &st) < 0)
    return -1;

参照file.c中filestat函数中下面这段代码

struct proc *p = myproc();
struct stat st;
if(copyout(p->pagetable, addr, (char *)&st, sizeof(st)) < 0)
      return -1;

从这两段代码中,我们大致知道我们需要做类似的事情,就是把sysinfo中的信息,复制给一个addr指针,传回用户空间,可以得到下面这段代码

uint64 
sys_sysinfo(void){
  struct sysinfo info;
  uint64 addr;
  struct proc *p=myproc();
  if(argaddr(0,&addr)<0){
    return -1;
  }
  info.nproc=get_nproc();
  info.freemem=get_freemem();
  if(copyout(p->pagetable, addr, (char *)&info, sizeof(info)) < 0)
      return -1;
  return 0;
}

要获取空闲内存量,请在kernel/kalloc.c中添加一个函数
要获取进程数,请在kernel/proc.c中添加一个函数

这里,我们要实现上面那段代码中的get_nproc和get_freemem函数,分别是获取进程数和空闲内存量

根据对应提示,仿照对应文件中的其他函数,可以容易写出来

uint64 
get_nproc(){
  struct proc *p;
  uint64 cnt=0;
  for(p = proc; p < &proc[NPROC]; p++) {
    acquire(&p->lock);
    if(p->state != UNUSED) {
      cnt++;
    } 
    release(&p->lock);
  }
  return cnt;
}

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

至此,执行make qemu,运行sysinfotest,PASS

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

学不会数据库

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

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

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

打赏作者

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

抵扣说明:

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

余额充值