其他分享
首页 > 其他分享> > MIT 6.828 Homework3:system call

MIT 6.828 Homework3:system call

作者:互联网

首先是要在syscall.c.中修改代码,使它能够为每个系统调用都能够输出一部分的跟踪信息,如图:

 

 于是找到syscall.c,这里没有什么特别好的方法,因此就用了简单粗暴的数组了:

static const char*sysname[]={
[SYS_fork]    "sys_fork",
[SYS_exit]    "sys_exit",
[SYS_wait]    "sys_wait",
[SYS_pipe]    "sys_pipe",
[SYS_read]    "sys_read",
[SYS_kill]    "sys_kill",
[SYS_exec]    "sys_exec",
[SYS_fstat]   "sys_fstat",
[SYS_chdir]   "sys_chdir",
[SYS_dup]     "sys_dup",
[SYS_getpid]  "sys_getpid",
[SYS_sbrk]    "sys_sbrk",
[SYS_sleep]   "sys_sleep",
[SYS_uptime]  "sys_uptime",
[SYS_open]    "sys_open",
[SYS_write]   "sys_write",
[SYS_mknod]   "sys_mknod",
[SYS_unlink]  "sys_unlink",
[SYS_link]    "sys_link",
[SYS_mkdir]   "sys_mkdir",
[SYS_close]   "sys_close",
};

然后加上这么一句即可:

void
syscall(void)
{
  int num;
 
  struct proc *curproc = myproc();
 
  num = curproc->tf->eax;

  if(num > 0 && num < NELEM(syscalls) && syscalls[num]) {
     
    cprintf("%s -> %d\n",
          syscall_name[num], syscalls[num]());
  } else {
    cprintf("%d %s: unknown sys call %d\n",
            curproc->pid, curproc->name, num);
    curproc->tf->eax = -1;
  }
}

接下来的第二个任务是要添加一个系统调用,这里首先注意到指导书上给出的这个指令:

grep -n uptime *.[chs]

直接在自己的终端打开使用即可:

 

首先需要创建date.c文件,并且完成main函数的代码:

#include "types.h"
#include "user.h"
#include "date.h"

int
main(int argc, char *argv[])
{
  struct rtcdate r;
  

  if (date(&r)) {
    printf(2, "date failed\n");
    exit();
  }

  // your code to print the time in any format you like...
  printf(1,"%d/%d/%d %d:%d:%d\n",r.year,r.month,r.day,r.hour,r.minute,r.second);

  exit();
}

rtcdate的结构如下:

struct rtcdate {
  uint second;
  uint minute;
  uint hour;
  uint day;
  uint month;
  uint year;
};

date函数取得时间后,对应时间存储在rtcdate中。因此直接简单打印出来即可。注意到date函数是有参数的,因此在打开最后的user.h文件中,定义如下:

int date(struct rtcdate*);

 

因此接下来的操作是如何实现对应的系统调用的代码:

int
sys_date(void){
  struct rtcdate*d;
  if(argptr(0,(void*)&d,sizeof(struct rtcdate))<0)
     return -1;
  cmostime(d);
  return 0;
}

这里的问题在于为什么要调用argptr函数。argptr函数:

int
argptr(int n, char **pp, int size)
{
  int i;
  struct proc *curproc = myproc();
 
  if(argint(n, &i) < 0)
    return -1;
  if(size < 0 || (uint)i >= curproc->sz || (uint)i+size > curproc->sz)
    return -1;
  *pp = (char*)i;
  return 0;
}

涉及到xv6的系统调用机制,简单来理解就是,这个函数是用来抓取系统调用的参数的。换言之,我们在date函数中,有一个结构体参数struct rtcdate,因此这里就可以通过argptr来获得传递进来的参数,然后接下来利用cmostime函数,最终让rtcdate得到时间数据。于是在之后切换回用户态时,此时我们的date.c文件中的main函数即可进行使用。于是我们就完成了这个系统调用的代码工作。

接下来需要注意的是,还要打开usys.s文件,进行对应的添加。然后在makefile对应的UPROGS添加_date即可。

另外,最好把之前进行描述的语句删除掉,否则显示端可能不会显示内容。

 

 之后打开终端,执行make qemu命令,唤醒我们的终端,然后再执行date命令即可完成上述操作。

以及接下来的挑战任务:

dup2函数介绍:
函数原型:int dup2(int oldfd,int newfd);
函数作用:为oldfd指向的文件分配一个新的文件描述符newfd,当newfd指向的文件已被系统使用时,关闭该文件,再进行分配,当newfd=oldfd时,不关闭newfd,分配成功后,oldfd与newfd将指向同一文件。
函数返回值:newfd。
于是问题在于怎么去找到对应的打开的文件表,它在这里:

 

 然后的话构思一下对应的系统调用函数,思路其实特别简单:

很明显oldfd和newfd正好是我们需要的,因此首先是获得这两个参数,并且进行一定的边界测试,测试通过后就可以进行对应的操作了:

int sys_dup2(void){
    int oldfd, newfd;
    if (argint(0, &oldfd) < 0 || argint(1, &newfd) < 0 || oldfd >= NOFILE || newfd >= NOFILE || oldfd < 0 || newfd < 0) {
        return -1;
    }
    struct file* oldfile = myproc()->ofile[oldfd];
    struct file* newfile = myproc()->ofile[newfd];
    if (!oldfile)
        return -1;
    else if (oldfd != newfd) {
        if (newfile)
            fileclose(newfd);//关闭对应的文件夹
        myproc()->ofile[newfd] = oldfile;
        filedup(oldfd);//计数+1
    }
    return newfd;
}

argint函数,有2个参数,第一个参数代表对应系统调用函数的第几个参数。例如我们将来传递进来的那2个参数分别是oldfd和newfd。oldfd是第一个,于是argint函数中的0代表了读取oldfd。1代表读取newfd。

 

标签:SYS,date,int,system,sys,oldfd,call,Homework3,newfd
来源: https://www.cnblogs.com/liyucheng0529/p/14551889.html