MIT 6.S081 Lab1

sleep.c

#include"../kernel/types.h"
#include"user.h"
int main(int argc,char* argv[])
{       
    if(argc != 2){
        fprintf(2,"Usage: sleep [microseconds]\n");
        exit(0);
    }       
    int second=atoi(argv[1]);
	sleep(second);
    exit(0);
}  

在这里插入图片描述

pingpong.c

原理
在这里插入图片描述

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

int main(int argc, char *argv[])
{
    int parent[2];
    int child[2];
    int p = pipe(parent);
    int c = pipe(child);

    char buf[1];

    if(p == -1) {
        printf("error create pipe parent");
    }

    if(c == -1) {
        printf("error create pipe child");
    }

    if (fork() == 0)  //child process, fork = 0
    {
        close(parent[1]); //close write of parent
        close(child[0]); //close read of child
        read(parent[0], buf, 1);
        printf("%d: received p%sng\n", getpid(), buf);
        write(child[1], "o", 1);
        close(child[1]); //close write of child
    }
    else if (fork() > 0)  //parent process, fork > 0
    {
        close(parent[0]); //close read of parent
        close(child[1]);  //close write of child
        write(parent[1], "i", 1);
        close(parent[1]); //close write of parent
        read(child[0], buf, 1);
        printf("%d: received p%sng\n", getpid(), buf);
    }
    exit(0);
}

在这里插入图片描述

primes.c

这题要麻烦一点,主要就是利用pipe和fork搞出一个素数筛子一样的东西
例如2,3,4,5,6,7,8,9,10,11中把素数筛出来,不过我们的这个程序是并行

这题主要做法就是主进程parent先fork了一个子进程child去执行sieve,然后主进程循环将2,3,4,…, 11输入pipe(parent),然后child子进程先看能不能从parent那里读到东西,读不到就exit,读的到就先fork一个子进程child2去执行sieve,child自己继续读parent的东西,以此类推

parent—>child—>child2—>child3—>…—>end
原理图
在这里插入图片描述在这里插入图片描述

#include "kernel/types.h"
#include "user/user.h"
void sieve(int* parent);
//we have two pipe: parent[2], child[2]
int main(int argc, char *argv[])
{
    int status;
    int parent[2];//create a pipe
    pipe(parent);

    if (fork() < 0) //fork error
    {
        fprintf(2, "fork error\n");
        exit(0);
    }
    if (fork() == 0) {// child process
        sieve(parent);// child process begin sieve
    }
    close(parent[0]);//close parent read port
    for (int i = 2; i <= 11; i++) {
        write(parent[1], &i, sizeof(int)); //write numbers into pipe
    }
    close(parent[1]); //close wiring of parent
    wait(&status);  //wait for all child process to end
    exit(0);
}

void sieve(int* parent)
{
    close(parent[1]);
    int ans;
    // read parent and  write it into n
    // if there is nothing to read, this child process can go die
    if (read(parent[0], &ans, sizeof(int)) == 0)
    {
        close(parent[0]);
        exit(0);
    }
    printf("prime %d\n",ans);
    int child[2];
    pipe(child);
    if (fork() == 0) // child process continue sieve
    {
        close(parent[0]);
        sieve(child); //start a new child process
    }
    close(child[0]);
    int prime = ans;
    while (read((parent[0]), &ans, sizeof(int)) != 0) {
        if (ans%prime != 0) {// is prime
            write(child[1], &ans, sizeof(int));
        }
    }
    close(parent[0]);
    close(child[1]);  //close writing of parent
    wait((int *)0);
    exit(0);
}

在这里插入图片描述

find.c

一些前置知识

fd

文件描述符是什么?
其实文件描述符(fd)就是一个数组下标,通过它我们能顺藤摸瓜的找到对应进程所指向的文件
在这里插入图片描述

fstat,stat

fstat是什么?
fstat 将fd所指的文件状态装入st所指的结构中(struct stat)

struct stat

stat是什么?
stat结构体是文件(夹)信息的结构体

struct dient

目录信息结构体

原理
下面是ls.c的实现代码,find.c其实只用在ls.c的基础上实现BFS就可以了

#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;
}

void ls(char *path)
{
    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:
        printf("%s %d %d %l\n", fmtname(path), st.type, st.ino, st.size);
        break;

    case T_DIR:
        if(strlen(path) + 1 + DIRSIZ + 1 > sizeof buf)
        {
            printf("ls: 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("ls: cannot stat %s\n", buf);
                continue;
            }
            printf("%s %d %d %d\n", fmtname(buf), st.type, st.ino, st.size);
        }
        break;
    }
    close(fd);
}

int
main(int argc, char *argv[])
{
  int i;
  if(argc < 2)
  {
    ls(".");
    exit(0);
  }
  for(i=1; i<argc; i++)
    ls(argv[i]);
  exit(0);
}

在这里插入图片描述

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


const char* this_dir=".";
const char* parent_dir="..";


char* fmtname(char *path)//把路径中最后一个名字分离出来
{
    static char buf[DIRSIZ+1];
    char *p;

    // find the filename before the last "/"
    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;
}


void search(char* dir_name,const char* file_name)
{
    char buf[512], *p;
    int fd;
    struct dirent de;
    struct stat st;
    //打开文件描述符
    if((fd = open(dir_name, 0)) < 0)
    {
        fprintf(2, "find: cannot open dir %s\n", dir_name);
        return;
    }
    // fstat 将fd所指的文件状态装入st所指的结构中(struct stat)
    // stat是文件(夹)信息结构体
    if(fstat(fd, &st) < 0)
    {
        fprintf(2, "find: cannot stat dir %s\n", dir_name);
        close(fd);
        return;
    }
    // 如果传入的是文件名(递归边界条件)
    if(st.type==T_FILE)
    {
        //和file_name进行匹配
        if(!strcmp(fmtname(dir_name),file_name))
        {
            printf("%s\n",dir_name);//直接打印目录
        }
        return;
    }
    // 如果是文件夹
    if(st.type==T_DIR)
    {
        if(strlen(dir_name) + 1 + DIRSIZ + 1 > sizeof buf)
        {
            printf("find: path too long\n");
            return;
        }
        // dir_name写入buf数组
        strcpy(buf, dir_name);
        p = buf+strlen(buf);//p是定位指针
        // p指向buf字符串的后一位
        *p++ = '/';
        //临时文件信息结构体
        struct stat st_tmp;
        //遍历目录下的文件
        //将fd读入de(struct dirent 目录项结构)
        while(read(fd, &de, sizeof(de)) == sizeof(de))
        {
            if(de.inum == 0)
                continue;
            memmove(p, de.name, DIRSIZ);//把文件名复制到字符串buf的最后面
            p[DIRSIZ] = 0;//这里准备遍历文件名 准备好生成文件或者目录的相对路径,存在buf里面,把这串字符的后一位置为0来生成字符串
            // 将buf的路径填入st_tmp(struct stat)
            if(stat(buf, &st_tmp) < 0)
            {
                //printf("ls: cannot stat %s\n", buf);
                continue;
            }
            if(st_tmp.type==T_FILE)//如果是普通文件
            {
                if(!strcmp(de.name,file_name))//找到文件
                {
                    printf("%s\n",buf);//打印文件的相对路径
                }
            }
            if(st_tmp.type==T_DIR)//如果是目录
            {
                //递归搜索,使用BFS遍历directory tree
                //禁止遍历. .. 这两个目录
                if((!strcmp(de.name,this_dir))||(!strcmp(de.name,parent_dir)))
                {
                    continue;
                }
                search(buf,file_name);//递归搜索
            }

        }
    }
    return;
}


int main(int argc, char *argv[])
{
    if(argc==2)
    {
        search(".",argv[2]);
    }
    else
    {
        search(argv[1],argv[2]);
    }
    exit(0);
}

在这里插入图片描述

xargs.c

先解释一些东西

argc:参数个数,表示argv数组的长度
argv:参数数组
|:管道符,负责管道重定向
exec:exec函数族提供了一个在进程中启动另一个程序执行的方法。 它可以根据指定的文件名目录名找到可执行文件,并用它来取代原调用进程数据段代码段堆栈段,在执行完之后,原调用进程的内容除了进程号外,其他全部被新的进程替换了
stdin:标准输入流

在本题中,shell将xargs的stdin重定向到pipe的读端,所以可以用read直接从0号文件stdin里读取数据

原理
在这里插入图片描述

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

int main(int argc,char* argv[])
{
    int status;
    if(argc==1)//如果xargs后面没参数
    {
        printf("Usage: xargs [OPTION]... COMMAND [INITIAL-ARGS]...\n");
        exit(0);
    }
    printf("--------argc--argv-------\n");
    printf("argc: %d\n",argc);
    for(int i=0;argv[i]!=NULL;i++)
    {
        printf("argv[%d]: %s\n",i,argv[i]);
    }
    printf("-----------end-----------\n");
    //指针数组argument
    char** argument=(char**)malloc(sizeof(char*)*MAXARG);//稍后传exec的参数


    //1. 从argv[1]开始是需要执行的程序和其参数。先将这部分参数传入argument中
    int i;
    //把xargs 后面的参数装入 argument
    for(i=0;i<argc-1;i++)
    {
        int len=strlen(argv[i+1])+1;
        //把argv[i+1]传到argument[i]
        argument[i]=(char*)malloc(sizeof(char)*len);//开辟空间
        strcpy(argument[i],argv[i+1]);//复制
    }


    //2. 现在传入管道流过来的数据, 然后存到argument中
    char buffer[60];//buffer是暂存空间
    char* p=buffer;//指示器,指示读入的地址

    /*shell的管道是把xargs的stdin文件重定向到了管道读端,
    所以可以用read直接从0号文件stdin里读取数据*/

    read(0,p,1);//从stdin读入一个字符

    while (*p)//不断读入,直到遇到空字符位置
    {
        if(*p=='\n')//读到一行末尾
        {
            *p='\0';//附加上空字符从而构成字符串
            //存入argument中
            int len=strlen(buffer)+1;
            argument[i]=(char*)malloc(sizeof(char)*len);
            strcpy(argument[i],buffer);
            //指示器复位到暂存空间开头
            p=buffer;
            //暂存空间清0
            memset(buffer,0,60);
            i++;
            read(0,p,1);
            continue;
        }
        p++;//读入本行下一个字符
        read(0,p,1);

    }
    printf("-----------argument------------\n");
    for(int j=0;j<i;j++)
    {
        printf("%s\n",argument[j]);
    }
    printf("arugument lens: %d\n",i);
    printf("-------------end---------------\n");
    argument[i]=0;//argument最后一项应该置为0?

    if(fork()==0)
    {
        //执行xargs后的命令
        if(exec(argv[1],argument)==-1)
        {
            fprintf(2,"xargs: exec error\n");
            exit(1);
        }
    }


    //记得收回子进程
    wait(&status);
    exit(0);
}

结果
在这里插入图片描述
做完之后收获超级大,MIT牛逼!!

  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值