MIT 6.s081 Lab1 util


寒假打算一边打ASC一边学点操作系统,于是打算开始做6.s801了。
版本是2020,源代码和环境配置在官网上写的很清楚,就暂时不写了。

Lab1是简单的Warmup以及对管道,多进程的基本应用,难度不算太大,顺便回忆一下当时写的shell和复习一下这方面的知识。教材方面需要看一看1.1~1.3

sleep

这个实验比较简单,就是让你实现sleep,直接用提供的系统调用就可以。注意要输出报错信息。
代码应该保存在user/sleep.c中,并且在Makefile的UPROGS中添加**$U/*_*sleep/**,后续实验同。

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

int main(int argc, char **argv)
{
    if (argc < 2)
    {
        fprintf(2, "Usage: sleep time...\n");
        exit(1);
    }
    int time = atoi(argv[1]);
    sleep(time);
    exit(0);
}

pingpong

该实验需要你完成以下功能:父进程向子进程发送ping,子进程收到ping后输出“pid received ping”,然后向父进程发送pong,父进程收到后做同样的操作。

考察对管道的简单应用,具体来说就是创建父->子,子->父两条管道,然后分别在对应的管道进行读写就可以了,及时close掉不用的fd可以避免被占用完。

没有试过只用一条管道,先咕咕。

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

int main(int argc, char **argv)
{
    int fd1[2];  //p->c
    int fd2[2];  //c->p
    
    pipe(fd1);
    pipe(fd2);
    
    if(fork()==0)
    {
        close(fd1[1]);
        close(fd2[0]);
        
        char buf[32];
        int len = read(fd1[0], buf, 32*sizeof(char));
        buf[len] = '\0';
        printf("%d: received %s\n", getpid(), buf);

        write(fd2[1], "pong", 4*sizeof(char));
        exit(0);
    }
    else
    {
        close(fd1[0]);
        close(fd2[1]);
        write(fd1[1], "ping", 4*sizeof(char));
        char buf[32];
        int len = read(fd2[0], buf, 32*sizeof(char));
        buf[len] = '\0';
        printf("%d: received %s\n", getpid(), buf);

        wait(0);
        exit(0);
    }
}

primes

这个实验蛮有意思的,用多进程实现小范围的埃氏筛法。

给的参考资料写的很明白了,每个进程会从管道读一些数,将第一个作为基本质数输出,然后将读入的数中不能整除基本质数的数写入子进程中,直到没有数写入。

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

void prime(int fd[])
{
    close(fd[1]);
    int send[36];
    int len = 0;
    int base = 0;
    int temp = 0;
    int cnt = 0;
    len = read(fd[0], &base, sizeof(int));
    if(base == 0) exit(0);
    printf("prime %d\n", base);

    while(len > 0)
    {
        len = read(fd[0], &temp, sizeof(int));
        if(len > 0)
            if(temp%base != 0)
                send[cnt++] = temp;
    }

    close(fd[0]);

    int n_fd[2];
    pipe(n_fd);

    if(fork()!=0)
    {
        close(n_fd[0]);
        write(n_fd[1], &send, cnt*sizeof(int));
        close(n_fd[1]);
        wait(0);
        exit(0);
    }
    else prime(n_fd);

}
int main()
{
    int nums[36];
    for(int i = 2;i < 36;i++)
        nums[i - 2] = i;
    
    int fd[2];
    pipe(fd);

    if(fork()!=0)
    {
        close(fd[0]);
        write(fd[1], &nums, 34*sizeof(int));
        close(fd[1]);
        wait(0);
        exit(0);
    }
    else
        prime(fd);
    return 0;
}

find

该实验要求你实现find命令。

可以参考给出的user/ls.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));
  buf[strlen(p)] = '\0';
  return buf;
}

void find(char *path, char *filename)
{
  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(strcmp(fmtname(path), filename) == 0)
        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 || strcmp(de.name, ".") == 0 || strcmp(de.name, "..") == 0)
        continue;
      memmove(p, de.name, DIRSIZ);
      p[DIRSIZ] = 0;
      find(buf, filename);
    }
    break;
  }
  close(fd);
}
int main(int argc, char **argv)
{
    if (argc < 3)
    {
        printf("error\n");
        exit(1);
    }
  find(argv[1], argv[2]);
  exit(0);
}

xargs

该实验要求实现xargs。

考察管道和fork & exec的调用,写过shell的对这个应该不陌生。循环地从标准输出读取数据,并以’\n’为为分割, 将每一行输出作为xargs 后命令的参数并执行,注意的一点是,利用 fork() 让命令在子进程中执行后,函数并没有结束,还需要继续读取,因此一些变量需要继续设置新的值。

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

int main(int argc, char **argv)
{
    char *cmd[MAXARG], *p;
    int cnt = 0, len;
    char buf[32], temp[32];
    int pos = 0;
    p = buf;
    for(int i = 1; i < argc; i++)
        cmd[cnt++] = argv[i];
    while((len = read(0, temp, sizeof(temp))) > 0)
    {
        for(int i = 0; i < len; i++)
        {
            if(temp[i] == ' ')
            {
                buf[pos++] = 0;
                cmd[cnt++] = p;
                p = &buf[pos];
            }
            else if(temp[i] == '\n')
            {
                buf[pos] = 0;
                cmd[cnt++] = p;
                cmd[cnt] = 0;
                pos = 0;
                p = buf;
                cnt = argc - 1;
                if(fork() == 0)
                    exec(argv[1], cmd);
                wait(0);
            }
            else
                buf[pos++] = temp[i];
        }
    }
    return 0;
}

文章作者: Watari
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Watari !
  目录