[mit6.s081] 笔记 Lab1: Unix utilities | Unix 实用工具

Boot xv6 (easy)

准备环境,编译编译器、QEMU,克隆仓库,略过。

$ git clone git://g.csail.mit.edu/xv6-labs-2020
$ cd xv6-labs-2020
$ git checkout util
$ make qemu

sleep (easy)

Implement the UNIX program sleep for xv6; your sleep should pause for a user-specified number of ticks. A tick is a notion of time defined by the xv6 kernel, namely the time between two interrupts from the timer chip. Your solution should be in the file user/sleep.c.

这个很简单,直接调用系统函数,sleep

#include"kernel/types.h"
#include"user/user.h"
int main(int argc,char*argv[])
{
    if(argc!=2)
    {
        printf("enter error\n");
        exit(0);
    }
    else 
    {
        sleep(atoi(argv[1]));
    }
    exit(0);
}

检测

~/v/MIT6.S081/xv6-labs-2020 util >1 !4 ?11 ./grade-lab-util sleep ok
make: “kernel/kernel”已是最新。
== Test sleep, no arguments == sleep, no arguments: OK (1.4s)
== Test sleep, returns == sleep, returns: OK (0.8s)
== Test sleep, makes syscall == sleep, makes syscall: OK (0.9s)

注意要在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\       # 在这添加

pingpong (easy)

Write a program that uses UNIX system calls to “ping-pong” a byte between two processes over a pair of pipes, one for each direction. The parent should send a byte to the child; the child should print “: received ping", where is its process ID, write the byte on the pipe to the parent, and exit; the parent should read the byte from the child, print “: received pong”, and exit. Your solution should be in the file user/pingpong.c.

这个也很简单,同过pipe创建管道,实现父子进程通信,注意在使用时,要将不使用的套接字关闭

#include "kernel/types.h"
#include "user/user.h"
int main()
{
    int p1[2], p2[2];
    pipe(p1);
    pipe(p2);
    int ret = fork();
    if (ret == 0) //子进程
    {
        char buf;
        close(p2[0]);         //关闭读端
        close(p1[1]);         //关闭写端
        read(p1[0], &buf, 1); //从父进程读
        printf("%d: received ping\n", getpid());
        write(p2[1], &buf, 1); //发送给子进程
        exit(1);
    }   
    else //父进程
    {
        char buf;
        close(p1[0]);         //关闭读端
        close(p2[1]);         //关闭写端
        write(p1[1], "!", 1); //发送给子进程
        read(p2[0], &buf, 1); //接收子进程
        printf("%d: received pong\n", getpid());
        wait(0);
    }
    return 0;
}

检测

~/v/MIT6.S081/xv6-labs-2020 util >1 !4 ?11 ./grade-lab-util pingpong
make: “kernel/kernel”已是最新。
== Test pingpong == pingpong: OK (1.1s)

primes (moderate)/(hard)

Write a concurrent version of prime sieve using pipes. This idea is due to Doug McIlroy, inventor of Unix pipes. The picture halfway down this page and the surrounding text explain how to do it. Your solution should be in the file user/primes.c.

在这里插入图片描述
这个还比较有意思,用多进程的方式实现素数筛
如上图所示,主进程将所有所要筛选范围内的数字(不包括1)按顺序发送给子进程,第一个子进程,收到的第一个数即为素数,剩下的数中筛除2的倍数在发送给下一个进程,后面过程以此类推,直至全部筛选完成。

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

void child_prime(int readpipe[2])
{
    int num;
    read(readpipe[0], &num, sizeof(num)); //读取一个
    if (num == -1)                        //全部读完
    {
        // printf("全部筛选完毕\n");
        exit(0);
    }
    printf("prime %d\n", num);

    int writepipe[2];
    pipe(writepipe);
    //int ret = fork();
    if (fork()==0) //子进程
    {
        close(readpipe[0]);  //子进程用不到
        close(writepipe[1]); //子进程只用到读
        child_prime(writepipe);
    }
    else //父进程
    {
        close(writepipe[0]); //用不到读端
        int temp = 0;
        while (read(readpipe[0], &temp, sizeof(temp)) &&temp!= -1)
        {
            if (temp % num != 0) //筛选
            {
                write(writepipe[1], &temp, sizeof(temp)); //写到管道
            }
        }
        temp = -1;
        write(writepipe[1], &temp, sizeof(temp)); //写入结束标志
        wait(0);
        exit(0);
    }
}

int main()
{
    int input[2];
    pipe(input);
    int ret = fork();
    if (ret == 0) //子进程
    {
        close(input[1]); //关闭写端
        child_prime(input);
        exit(0);
    }
    else //父进程
    {
        int i;
        close(input[0]); //关闭读端
        for (i = 2; i <= 35; i++)
        {
            write(input[1], &i, sizeof(i));
        }
        i = -1;
        write(input[1], &i, sizeof(i)); //告诉子线程,输入完毕
    }
    wait(0);
    exit(0); //退出
}

检测

 $  primes
    prime 2
    prime 3
    prime 5
    prime 7
    prime 11
    prime 13
    prime 17
    prime 19
    prime 23
    prime 29
    prime 31

~/v/MIT6.S081/xv6-labs-2020 util >1 !4 ?11 ./grade-lab-util primes ok
make: “kernel/kernel”已是最新。
== Test primes == primes: OK (0.8s)

find (moderate)

Write a simple version of the UNIX find program: find all the files in a directory tree with a specific name. Your solution should be in the file user/find.c.

这个比较简单,借鉴user/ls.c,就可以写出来

#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
#include "kernel/fs.h"
#define NAME 512
void find(char *path, char *target)
{
    char buf[512], *p;
    int fd;
    struct dirent de;
    struct stat st;
    if ((fd = open(path, 0)) < 0) //打开失败
    {
        printf("find: cannot open %s\n", path);
        return;
    }
    if (fstat(fd, &st) < 0)
    {
        printf("find: 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)
                continue;
            memmove(p, de.name, DIRSIZ);
            p[DIRSIZ] = 0;
            if (stat(buf, &st) < 0)
            {
                printf("find: connot stat %s\n", buf);
                continue;
            }
            if (strcmp(buf + strlen(buf) - 2, "/.") != 0 && strcmp(buf + strlen(buf) - 3, "/..") != 0)
            {
                find(buf, target); //递归查找
            }
        }
        break;
    default:
        break;
    }
    close(fd);
}
int main(int argc, char *argv[])
{
    if (argc < 3)
    {
        printf("find : error\n");
        exit(0);
    }
    else
    {
        char target[NAME];
        target[0] = '/';
        strcpy(target + 1, argv[2]);
        find(argv[1], target);
        exit(0);
    }
}

检测

 $ find . b
 ./b
 ./a/b
 ./a/aa/b

~/v/MIT6.S081/xv6-labs-2020 util >1 !4 ?11 ./grade-lab-util find ok
make: “kernel/kernel”已是最新。
== Test find, in current directory == find, in current directory: OK (1.1s)
== Test find, recursive == find, recursive: OK (1.1s)

xargs (moderate)

Write a simple version of the UNIX xargs program: its arguments describe a command to run, it reads lines from the standard input, and it runs the command for each line, appending the line to the command’s arguments. Your solution should be in the file user/xargs.c.

这个思路也很简单,不过多赘述

#include "../kernel/types.h"
#include "../kernel/stat.h"
#include "../user/user.h"
#define NULL 0
#define ARG 64
void task(char **argv)
{
    if (fork() == 0) //子进程
    {
        exec(argv[0], argv);
        exit(0);
    }
    return;
}
int main(int argc, char *argv[])
{
    int i = 0;
    char buf[1024];              //存放所有参数(内存池)
    char *ntr = buf, *ptr = buf; //指向一个参数开始和结束的位置
    char *arg[ARG];              //存放参数的指针数组,每个元素指向一个字符串,也就是参数
    char **temp = arg;           //指向指针数组起点
    for (i = 1; i < argc; i++)   //循环将参数加入素组当中
    {
        *temp = argv[i];
        temp++;
    }
    char **str = temp;           //置为开始位置
    while (read(0, ptr, 1) != 0) //循环读取参数(从标准输入)
    {
        if (*ptr == '\n' || *ptr == ' ') //一行参数读入完成
        {
            char t = *ptr;
            *ptr = '\0'; //将空格替换成'\0'
            *(str++) = ntr;
            ntr = ptr + 1;    //改变一个参数的开始位置
                              // printf("%c\n",t);
            if (t == '\n') //一行执行完毕
            {
                *str = NULL; //表示该行参数结束
                task(arg); //交给子进程执行任务
                str = temp; //重新回到开始位置
            }
        }
        ptr++;
    }
    if (str != temp) //如果最后一行结束时不是'\n'
    {
        *ptr = '\0';
        *(str++) = ntr;
        *str = NULL;
        task(arg);
    }
    while (wait(0) != -1)
        ; //循环回收子进程
    exit(0);
}

检测:

    $ echo hello too | xargs echo bye
    bye hello too

~/v/MIT6.S081/xv6-labs-2020 util >1 !4 ?11 ./grade-lab-util xargs ok
make: “kernel/kernel”已是最新。
== Test xargs == xargs: OK (0.8s)

  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

binary~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值