MIT6.S081之实用程序

前言

第一个实验是在XV6系统上实现五个实用程序。虽然不难,但是我写了好久……

实验

sleep

sleep本身不需要实现,只需要运行即可。

源代码

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

int main(int argc,char* argv[]){
    if(argc != 2){
        printf("Sleep needs one argument!\n"); //检查参数数量是否正确
        exit(-1);
    }
    int ticks = atoi(argv[1]); //将字符串参数转为整数
    sleep(ticks);              //使用系统调用sleep
    printf("(nothing happens for a little while)\n");
    exit(0); //确保进程退出
}

编译运行

  1. 修改Makefile
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\ # 添加sleep
  1. 运行
sudo make qume

在这里插入图片描述

pingpong

要求

实现两个进程在管道两侧来回通信。
父进程将”ping”写入管道,子进程从管道将其读出并打印。子进程从父进程收到字符串后,将”pong“写入另一个管道,然后由父进程从该管道读取并打印。

原理

通过定义两个管道fp和sp,实现父子进程传输消息

注意,进程通常只持有某个管道的读出端或者写入端,因此使用的时候需要将另一端关闭。

源代码

#include "kernel/types.h"
#include "user.h"
int main(int argc,char* argv[])
{
    int fp[2],sp[2];
    pipe(fp);//父进程写入,子进程读取
    pipe(sp);
    printf("program start!\n");
    int pid = fork();
    if(pid<0)
    {
        printf("error!");
    }
    else if(pid == 0)
    {
        /*子进程 */
        char *buffer = "    ";
        close(fp[1]); // 关闭写端
        read(fp[0], buffer, 4);//阻塞等待
        printf("%d: received %s\n",getpid(),buffer);
        close(fp[0]); // 读取完成,关闭读端
        char *intput = "pong";
        close(sp[0]); // 关闭读端
        write(sp[1], intput, 4);
        close(sp[1]); // 写入完成,关闭写端

    }
    else{
        /*父进程*/ 
        char *buffer = "ping";
        close(fp[0]); // 关闭读端
        write(fp[1], buffer, 4);
        close(fp[1]); // 写入完成,关闭写端
        close(sp[1]); // 关闭写端
        read(sp[0], buffer, 4);
        printf("%d: received %s\n",getpid(),buffer);
        close(sp[0]); // 读取完成,关闭读端
    }
    exit(0);
}

运行结果

在这里插入图片描述

primes

要求

使用管道实现“质数筛选”, 输出2~35之间的而所有质数。

原理

筛选思路:

  1. 主进程将所有数据输入到管道的左侧
  2. 子进程从管道读出并筛选出第一个数字x,排除掉x的倍数,其他数字再写入下一管道;
  3. 重复步骤二,直到管道中没有数字
    在这里插入图片描述

源代码

#include "kernel/types.h"
#include "user.h"
#include <stddef.h>
void mapping(int n, int fd[])
{
    close(n);//关闭文件描述符n,令n映射到fd[n]
    dup(fd[n]);
    close(fd[0]);
    close(fd[1]);
}
void primes()
{
    int fd[2];
    pipe(fd);
    int prime;//当前的质数
    int ref = read(0, &prime, sizeof(int));
    if(ref == 0)return;//没有质数了
    printf("prime %d\n", prime);
    int pid = fork();
    if(pid == 0)
    {
        int num;
        mapping(1, fd);//将管道映射到1上
        while(read(0,&num, sizeof(int)))
        {
            if(num%prime == 0)continue;
            write(1, &num, sizeof(int));
        }
    }
    else 
    {
        wait(NULL);
        mapping(0, fd);//将管道映射到0上
        primes();
    }
}
int main(int argc,char* argv[])
{
    int fd[2];
    pipe(fd);//父进程写入,子进程读取
    printf("program start!\n");
    int pid = fork();
    if(pid<0)
    {
        printf("error!");
    }
    else if(pid == 0)
    {
        /*子进程 */
        mapping(1,fd);
        for(int i = 2;i <= 35; i++)//将所有数字塞入管道
            write(1, &i, sizeof(int));

    }
    else{
        /*父进程*/ 
        wait(NULL);//等待子进程结束
        mapping(0, fd);
        primes();
    }
    exit(0);
}

运行结果

在这里插入图片描述

find

要求

在目录树中查找名称与字符串匹配的所有文件,输出文件的相对路径。

原理

借鉴ls指令的写法,读取路径下的文件名,如果是文件,就与寻找的文件名比较,如果是文件夹,就递归继续寻找该文件夹。

源代码

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

char* fmtname(char *path)
{
  char *p;

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

  return p;
}

void find(char *path, char *file_name)
{
  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;
  }

  if(st.type != T_DIR)
  {
    fprintf(2, "find: cannot find in %s\n", path);
    close(fd);
    return;
  }
  if(strlen(path) + 1 + DIRSIZ + 1 > sizeof buf){//路径太长了
    return;
  }

  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;
    }
    char *name = fmtname(buf);
    switch (st.type)
    {
    case T_FILE:
      if(strcmp(name, file_name) == 0)
      {
        printf("%s\n", buf);
      }
      break;
    case T_DIR:
      if(strcmp(name, ".") == 0 || strcmp(name, "..") == 0)
        continue;//不能是本层或者上层
      find(buf, file_name);
      break;
    default:
      break;
    }
  }
  close(fd);
}

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

  if(argc < 3){
    printf("please input find [path] [file_name]\n");
    exit(0);
  }
  find(argv[1], argv[2]);
  exit(0);
}

运行结果

在这里插入图片描述

xargs

要求

从标准输入中读取行并 为每行运行一次 指定的命令,且将该行作为命令的参数提供。

原理

这个小实验主要是对于实现效果的理解。

  1. |
    命令行中的|会将左边的命令的输出通过管道传递到右侧,可以直接从标准输入中读取字符串。
  2. exec函数
    exec接收的二维参数数组argv,argv[0]必须是该命令本身,最后一个参数argv[size-1]必须为0,否则将执行失败。
char *argv[]={"echo","hello",0};
exec(argv[0],argv);

源代码

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

int main(int argc, char* argv[]) {
   if(argc < 2){
       printf("error inputs");
       exit(0);
   }//参数不够
   char *cmd = argv[1];
   char *argvs[MAXARG];
   for(int i=1;i<argc;i++)
   {
       argvs[i-1]=argv[i];
   }
   char buff[1024];
    while(read(0,&buff,sizeof(buff)))//读取|右边的命令输出或者等待输出
    {
        int len = strlen(buff);
        argvs[argc-1]=&buff[0];
        for(int i=0;i<len;i++)
        {
            if(buff[i]=='\n')// 默认 -n1
            {
                if(fork()==0)
                {
                    buff[i]=0;
                    argvs[argc]=0;//命令的最后一个参数为0
                    exec(cmd,argvs);//执行每一行命令
                }
                wait(0);//等待子进程结束
                argvs[argc-1]=&buff[i+1];//下一行命令的首地址
            }
        }
    }
    exit(0);
}

运行结果

运行命令 xargstest.sh

mkdir a
echo hello > a/b
mkdir c
echo hello > c/b
echo hello > b
find . b | xargs grep hello

在这里插入图片描述

结语

第一个实验就耗费了大量的时间,有几个实验还借鉴了别人的写法。考虑到我不是科班出身,之后的实验不如趁早观看别人的写法,能学到东西就好。

如有兴趣,欢迎来访我的个人博客

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值