XV6學習(2)Lab syscall

實驗的代碼放在了Github上。html

第二個實驗是Lab: system calls
這個實驗主要就是本身實現幾個簡單的系統調用並添加到XV6中。git

XV6系統調用

添加系統調用主要有如下幾步:github

user/user.h中添加系統調用函數的定義。數組

user/usys.pl中添加入口,這個文件將會在make後生成user/usys.S文件,在該彙編文件中,每一個函數就只有三行,將系統調用號經過li(load imm)存入a7寄存器,以後使用ecall進入內核態,最後返回。函數

fork:
 li a7, SYS_fork
 ecall
 ret

kernel/syscall.h中定義系統調用號。ui

kernel/syscall.csyscalls函數指針數組中添加對應的函數。在syscall函數中,先讀取trapframe->a7獲取系統調用號,以後根據該系統調用號查找syscalls數組中的對應的處理函數並調用。this

System call tracing (moderate)

先在proc結構體中添加一個trace_mask字段,以後在fork函數中複製該字段到新進程。指針

在系統調用sys_trace中就只要經過argint函數讀取參數,而後設置給trace_mask字段就好了。code

最後修改syscall,當系統調用號和trace_mask匹配時就打印相關信息。htm

// proc.h
struct proc {
  ...
  // this is for sys_trace()
  uint trace_mask;
};

// proc.c
int
fork(void)	fork(void)
{
  ...
  // copy trace mask
  np->trace_mask = p->trace_mask;
  ...
}

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

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

  num = p->trapframe->a7;
  if(num > 0 && num < NELEM(syscalls) && syscalls[num]) {
    uint64 ret = syscalls[num]();
    p->trapframe->a0 = ret;
    if((1 << num) & p->trace_mask) {
      printf("%d: syscall %s -> %d\n", p->pid, syscall_name[num], ret);
    }
  } else {
    printf("%d %s: unknown sys call %d\n",
            p->pid, p->name, num);
    p->trapframe->a0 = -1;
  }
}

Sysinfo (moderate)

這一個系統調用主要就是要實現freememnproc兩個函數來統計內存和進程。

// sysproc.c
uint64
sys_sysinfo(void)
{
  uint64 info; // user pointer
  struct sysinfo kinfo;
  struct proc *p = myproc();
  if(argaddr(0, &info) < 0){
    return -1;
  }
  kinfo.freemem = freemem();
  kinfo.nproc = nproc();
  if(copyout(p->pagetable, info, (char*)&kinfo, sizeof(kinfo)) < 0){
    return -1;
  }
  return 0;
}

閱讀kallockfree兩個函數就能夠知道,kmem.freelist是一個保存了當前空閒內存塊的鏈表,所以只須要統計這個鏈表的長度再乘以PGSIZE就能夠獲得空閒內存。

// kalloc.c
uint64
freemem(void)
{
  uint64 counter = 0;
  struct run *r;
  acquire(&kmem.lock);
  r = kmem.freelist;
  while(r){
    r = r->next;
    ++counter;
  }
  release(&kmem.lock);
  return counter * PGSIZE;
}

閱讀procdump和相關代碼就能夠知道,XV6的進程結構體保存在proc[NPROC]數組當中。而proc->state字段保存了PCB的當前狀態,有UNUSED、SLEEPING、RUNNABLE、RUNNING、ZOMBIE五種狀態。所以只須要遍歷這個數組,而後統計state不是UNUSED狀態的就好了。

// proc.c
uint64
nproc(void)
{
  uint64 counter = 0;
  struct proc *p;

  for(p = proc; p < &proc[NPROC]; p++) {
    acquire(&p->lock);
    if(p->state != UNUSED) {
      ++counter;
    }
    release(&p->lock);
  }
  return counter;
}
相關文章
相關標籤/搜索