这个实验主要学习了常用的一些系统调用。
Lab 1: Unix utilities
Boot xv6 (easy)
git克隆,切换分支,qemu。根据要求进行操作即可。
$ git clone git://g.csail.mit.edu/xv6-labs-2020
$ cd xv6-labs-2020
$ git checkout util
$ make qemu
 
sleep (easy)
#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
int main(int argc ,char *argv[])
{
    if(argc < 2 )
    {
        fprintf(2,"please enter a number!");
        exit(1);
    }else{
        int n = atoi(argv[1]);
        sleep(n);
        exit(0);
    }
}
 
在 Makefile 中将 sleep 加入构建目标里。
UPROGS=\
	$U/_cat\
	$U/_echo\
	$U/_forktest\
	$U/_grep\
	$U/_init\
	$U/_kill\
	$U/_ln\
	$U/_ls\
	$U/_mkdir\
	$U/_rm\
	$U/_sh\
	$U/_stressfs\
	$U/_usertests\
	$U/_grind\
	$U/_wc\
	$U/_zombie\
	$U/_sleep\ .   # here !!!
 
pingpong (easy)
管道题,使用 fork() 复制本进程创建子进程,然后使用管道进行相互通信。
#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
int main(int argc ,char *argv[])
{
    int pp2c[2],pp2p[2];
    pipe(pp2c);
    pipe(pp2p);
    int n = fork();
    if(n != 0 ){
        write(pp2c[1],"a",1);
        char buff;
        read(pp2p[0],&buff,1);
        printf("%d: received pong\n",n);
    }else{
        char buff;
        read(pp2c[0],&buff,1);
        printf("%d: received ping\n",n);
        write(pp2p[1],&buff,1);
        
    }
    exit(0);
}
 
primes (moderate) / (hard)
观察下图进行进行理解,使用fork实现素数筛的功能。
 
// primes.c
#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
void sieve(int pleft[2]){
    int p ;
    read(pleft[0] ,&p,sizeof(p));
    if(p == -1){
        exit(0);
    }
    printf("prime %d\n", p);
    int pright[2];
    pipe(pright);
    if(fork() == 0){
        // 子进程
        close(pright[1]);
        close(pleft[0]);
        sieve(pright);
    }else{
        close(pright[0]);
        int buff ;
        while(read(pleft[0] ,&buff,sizeof(buff)) && buff != -1){
            if(buff %p != 0 ){
                write(pright[1] ,&buff,sizeof(buff));
            }
        }
        buff = -1;
        write(pright[1] ,&buff,sizeof(buff));
        wait(0);
        exit(0);
    }
}
int main(int argc,char* argv[]){
    int inputpipe[2];
    pipe(inputpipe);
    if(fork() == 0){
        // 子进程
        close(inputpipe[1]);
        sieve(inputpipe);
        exit(0);
    }else{
        close(inputpipe[0]);
   
        int i ;
        for( i = 2 ; i <=35;i++){
            write(inputpipe[1] ,&i,sizeof(i) );
            
        }
        i =-1;
        write(inputpipe[1] ,&i,sizeof(i) );
        
    }
    wait(0);
    exit(0);
}
 
find (moderate)
根据ls.c 改造得到
#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
#include "kernel/fs.h"
void find(char *path,char *target)
{
  char buf[512], *p;
  int fd;
  struct dirent de;
  struct stat st;
  if((fd = open(path, 0)) < 0){
    fprintf(2, "ls: cannot open %s\n", path);
    return;
  }
  if(fstat(fd, &st) < 0){
    fprintf(2, "ls: cannot stat %s\n", path);
    close(fd);
    return;
  }
  switch(st.type){
  case T_FILE:
    if(strcmp(path+strlen(path) - strlen(target) ,target) == 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;
      if(stat(buf, &st) < 0){
        printf("find: cannot stat %s\n", buf);
        continue;
      }
      // printf(buf);
      // printf("\n");
    		find(buf, target); // 递归查找
		
    }
    break;
  }
  close(fd);
}
int main(int argc, char *argv[])
{
  
	if(argc < 3){
		exit(0);
	}
	char target[512];
	target[0] = '/'; // 为查找的文件名添加 / 在开头
	strcpy(target+1, argv[2]);
	find(argv[1], target);
	exit(0);
}
 
xargs (moderate)
xargs介绍
整体思路:
- 将xargs命令传入的参数保存至指针数组,每个指针指向一个参数;
 - 解析输入参数,如果遇到’ ’ 或者\n 就将参数保存至指针数组,每次读取完成一行就使用exec进行运行
 - 最后一行进行单独判断运行,万一最后一行没有换行符
 
// xargs.c
#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
#include "kernel/fs.h"
void run(char *program , char ** args)
{
    if(fork() == 0 ){
        exec(program,args);
        exit(0);
    }
    return ;
}
int main(int argc,char* argv[]){
    char buf[2048]; // 读入时使用的内存池
	char *p = buf, *last_p = buf; // 当前参数的结束、开始指针
	char *argsbuf[128]; // 全部参数列表,字符串指针数组,包含 argv 传进来的参数和 stdin 读入的参数
	char **args = argsbuf; // 指向 argsbuf 中第一个从 stdin 读入的参数
    for(int i=1;i<argc;i++) {
		// 将 argv 提供的参数加入到最终的参数列表中
		*args = argv[i];
		args++;
	}
    char **pa = args;
    while(read(0,p,1) != 0 ){
        if(*p == ' ' || *p == '\n'){
            *p = '\0';
            *(pa++) = last_p;
            last_p = p+1;
            
            if(*p == '\n'){
    
                
                *pa = 0;
                run(argv[1],argsbuf);
                pa = args;
            }
        }
        p++;
    }
    if(pa != args) { // 如果最后一行不是空行
		// 收尾最后一个参数
      
		*p = '\0';
		*(pa++) = last_p;
		// 收尾最后一行
		*pa = 0; // 参数列表末尾用 null 标识列表结束
		// 执行最后一行指令
		run(argv[1], argsbuf);
	}
    while(wait(0) != -1) {}; 
    exit(0);
}
                











![2023年中国稻谷加工机械分类、市场规模及发展前景分析[图]](https://img-blog.csdnimg.cn/img_convert/e03c9ee1d75754bc332abeb37ae89299.png)






