MIT 6.828 - 1. Lab 01: Xv6 and Unix utilities


實驗總結

  1. 本次實驗用時約五個小時,足證我代碼能力之退化。
  2. 對於實驗三中難懂的 redirect(), twd2 認為可以往 xv6 中加一個 dup2 函數,我表示同意。需要進一步研究 xv6 結構,確定如何添加。

遇到的其他問題包括:

  1. 突然間發現 gcc 不認 uint 類型了。經檢查發現用戶態程序需要手動 #include "kernel/types.h" ,不然會爆炸。

測試結果:

$ make grade
# ... lines omitted
Score: 100/100

0. 實驗准備

實驗指導連接

上來直接:

$ cd xv6-riscv-fall19
$ git checkout util

實驗指導簡要介紹了如何把 xv6 跑起來(make then make qemu),如何交作業(make handin),如何測試成績(make grade)。

下面介紹各個子任務如何寫。

1. sleep

顧名思義寫一個 sleep 例程,休眠一定的 tick 數,tick 的定義是時間中斷。

Hints:
Look at some of the other programs in user/ to see how you can obtain the command-line arguments passed to a program. If the user forgets to pass an argument, sleep should print an error message.
The command-line argument is passed as a string; you can convert it to an integer using atoi (see user/ulib.c).
Use the system call sleep (see user/usys.S and kernel/sysproc.c).
Make sure main calls exit() in order to exit your program.
Add the program to UPROGS in Makefile and compile user programs by typing make fs.img.
Look at Kernighan and Ritchie's book The C programming language (second edition) (K&R) to learn about C.

首先 make clean,然后照貓畫虎寫一下 user/sleep.c

#include "kernel/types.h"
#include "user/user.h"

int main(int argc, char *argv[]) {
  if (argc != 2)
    write(2, "Error message", strlen("Error message"));

  int x = atoi(argv[1]);

  sleep(x);

  exit();
}

按照說明修改 Makefile ,給 UPROG 變量追加一個項目,運行即可。

2. pingpong

如法炮制。

#include "kernel/types.h"
#include "user/user.h"

int main(int argc, char *argv[]) {
  int parent_fd[2], child_fd[2];
  pipe(parent_fd);
  pipe(child_fd);
  char buf[64];

  if (fork()) {
    // Parent
    write(parent_fd[1], "ping", strlen("ping"));
    read(child_fd[0], buf, 4);
    printf("%d: received %s\n", getpid(), buf);
  } else {
    // Child
    read(parent_fd[0], buf, 4);
    printf("%d: received %s\n", getpid(), buf);
    write(child_fd[1], "pong", strlen("pong"));
  }

  exit();
}

3. primes

照貓畫虎。

負責我的課程助教 twd2 認為,redirect(int, int[]) 這個函數有問題,原因在於 xv6 沒有 dup2(int, int) ,這個函數是網上抄的。

#include "kernel/types.h"
#include "user/user.h"

void source() {
  int i;
  for (i = 2; i < 36; i++) {
    write(1, &i, sizeof(i));
  }
}

void cull(int p) {
  int n;
  while (read(0, &n, sizeof(n))) {
    if (n % p != 0) {
      write(1, &n, sizeof(n));
    }
  }
}

void redirect(int k, int pd[]) {
  close(k);
  dup(pd[k]);
  close(pd[0]);
  close(pd[1]);
}

void sink() {
  int pd[2];
  int p;

  if (read(0, &p, sizeof(p))) {
    printf("prime %d\n", p);
    pipe(pd);
    if (fork()) {
      redirect(0, pd);
      sink();
    } else {
      redirect(1, pd);
      cull(p);
    }
  }
}

int main(int argc, char *argv[]) {

  int pd[2];
  pipe(pd);

  if (fork()) {
    redirect(0, pd);
    sink();
  } else {
    redirect(1, pd);
    source();
  }

  exit();
}

4. find

Bonus 是加 regex 支持,好,抄 user/grep.c 即可。

#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
#include "kernel/fs.h"

char*
fmtname(char *path)
{
  static char buf[DIRSIZ+1];
  char *p;

  // Find first character after last slash.
  for(p=path+strlen(path); p >= path && *p != '/'; p--)
    ;
  p++;

  // Return blank-padded name.
  if(strlen(p) >= DIRSIZ)
    return p;
  memmove(buf, p, strlen(p));
  memset(buf+strlen(p), ' ', DIRSIZ-strlen(p));
  return buf;
}

// Regexp matcher from Kernighan & Pike,
// The Practice of Programming, Chapter 9.

int matchhere(char*, char*);
int matchstar(int, char*, char*);

int
match(char *re, char *text)
{
  if(re[0] == '^')
    return matchhere(re+1, text);
  do{  // must look at empty string
    if(matchhere(re, text))
      return 1;
  }while(*text++ != '\0');
  return 0;
}

// matchhere: search for re at beginning of text
int matchhere(char *re, char *text)
{
  if(re[0] == '\0')
    return 1;
  if(re[1] == '*')
    return matchstar(re[0], re+2, text);
  if(re[0] == '$' && re[1] == '\0')
    return *text == '\0';
  if(*text!='\0' && (re[0]=='.' || re[0]==*text))
    return matchhere(re+1, text+1);
  return 0;
}

// matchstar: search for c*re at beginning of text
int matchstar(int c, char *re, char *text)
{
  do{  // a * matches zero or more instances
    if(matchhere(re, text))
      return 1;
  }while(*text!='\0' && (*text++==c || c=='.'));
  return 0;
}

void
find(char *path, char *re)
{
  char buf[512], *p;
  int fd;
  struct dirent de;
  struct stat st;

  if((fd = open(path, 0)) < 0){
    fprintf(2, "find: cannot open %s\n", path);
    return;
  }

  if(fstat(fd, &st) < 0){
    fprintf(2, "find: cannot stat %s\n", path);
    close(fd);
    return;
  }

  switch(st.type){
  case T_FILE:
    if(match(re, fmtname(path)))
      printf("%s\n", path);
    break;

  case T_DIR:
    if(strlen(path) + 1 + DIRSIZ + 1 > sizeof buf){
      printf("find: path too long\n");
      break;
    }
    strcpy(buf, path);
    p = buf+strlen(buf);
    *p++ = '/';
    while(read(fd, &de, sizeof(de)) == sizeof(de)){
      if(de.inum == 0)
        continue;
      memmove(p, de.name, DIRSIZ);
      p[DIRSIZ] = 0;
      if(stat(buf, &st) < 0){
        printf("find: cannot stat %s\n", buf);
        continue;
      }

      if(strlen(de.name) == 1 && de.name[0] == '.')
        continue;
      if(strlen(de.name) == 2 && de.name[0] == '.' && de.name[1] == '.')
        continue;

      find(buf, re);
    }
    break;
  }
  close(fd);
}


int main(int argc, char *argv[]) {
  if(argc <= 2)
    fprintf(2, "find: not enough params provided");
  find(argv[1], argv[2]);
  
  exit();
}

5. xargs

需要參考 user/sh.cuser/cat.c 兩個例程。

#include "kernel/types.h"
#include "user/user.h"

int main(int argc, char *argv[]) {
  char buf2[512];
  char buf[32][32];
  char *pass[32];

  for (int i = 0; i < 32; i++)
    pass[i] = buf[i];

  int i;
  for (i = 1; i < argc; i++)
    strcpy(buf[i - 1], argv[i]);

  int n;
  while ((n = read(0, buf2, sizeof(buf2))) > 0) {
    int pos = argc - 1;
    char *c = buf[pos];
    for (char *p = buf2; *p; p++) {
      if (*p == ' ' || *p == '\n') {
        *c = '\0';
        pos++;
        c = buf[pos];
      } else
        *c++ = *p;
    }
    *c = '\0';
    pos++;
    pass[pos] = 0;

    if (fork()) {
      wait();
    } else
      exec(pass[0], pass);
  }

  if (n < 0) {
    printf("xargs: read error\n");
    exit();
  }

  exit();
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM