MIT 6.1810: Xv6 and Unix utilities

警告
本文最后更新于 2023-03-04,文中内容可能已过时。

MIT 6.1810 中第一个 lab 的 solution

Xv6 and Unix utilities

第一个lab的所有都是在Makefile中添加要编译的目标,并且在user/目录下新建文件。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
...
	$U/_rm\
	$U/_sh\
	$U/_stressfs\
	$U/_usertests\
	$U/_grind\
	$U/_wc\
	$U/_zombie\
	$U/_sleep\
	$U/_pingpong\
	$U/_primes\
	$U/_find\
	$U/_xargs\
...

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.

1
2
3
4
5
6
$ make qemu
...
init: starting sh
$ sleep 10
(nothing happens for a little while)
$
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
#include "kernel/types.h"
#include "user/user.h"

int main(int argc, char* argv[]){
    if((argc != 2) || !atoi(argv[1])){
        fprintf(2, "sleep: error arguments\n");
        exit(1);
    }
    sleep(atoi(argv[1]));
    exit(0);
}

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.

1
2
3
4
5
6
7
$ make qemu
...
init: starting sh
$ pingpong
4: received ping
3: received pong
$

这里的pingpong我实现的并不是课程网站这样的,而是类似xv6-book中第一章Exercises描述的那样。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include "kernel/types.h"
#include "user/user.h"

int main(void){
    char buf[8];
    int p[2];
    if(pipe(p)){
        fprintf(2, "pingpong: pipe error\n");
        exit(1);
    }
    if(fork() == 0){
          read(p[0], buf, 4);
          printf("%d: received %s\n", getpid(), buf);
          write(p[1], "pong", 4);
    }else{
          write(p[1], "ping", 4);
          read(p[0], buf, 4);
          printf("%d: received %s\n", getpid(), buf);
    }
    wait(0);
    exit(0);
}

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
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
$ make qemu
...
init: starting sh
$ primes
prime 2
prime 3
prime 5
prime 7
prime 11
prime 13
prime 17
prime 19
prime 23
prime 29
prime 31
$
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include "kernel/types.h"
#include "user/user.h"

int main(void){
    int p[2];
    int buf[1];
    int i, n, flag = 0;
    if(pipe(p)){
        fprintf(2,"primes: pipe error\n");
        exit(1);
    }

    if(fork() == 0){
        for(i = 2; i < 36; i++){
            fprintf(p[1],"%c", i);
        }
        exit(0);
    }else{
      close(p[1]);
    }

    while(read(p[0], buf, 1)){
        n = buf[0];
        for(i = 1; i < n; i++)
            if(!(n % i))  flag++;
        if(flag == 1)
            printf("prime %d\n", n);
        flag = 0;
    }
    exit(0);
}

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.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
$ make qemu
...
init: starting sh
$ echo > b
$ mkdir a
$ echo > a/b
$ mkdir a/aa
$ echo > a/aa/b
$ find . b
./b
./a/b
./a/aa/b
$

这里貌似少整了一个东西,但是懒得看了,能跑就行[doge]。

这里大多借鉴的ls的代码实现

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
#include "kernel/fs.h"

void find(char *path, char *name);

int main(int argc, char* argv[])
{
    if(argc != 3){
        fprintf(2, "find: error arguments\n");
        exit(-1);
    }
    char *path = argv[1];
    char *name = argv[2];
    find(path, name);
    exit(0);
}

void find(char *path, char *name){
    char buf[512], *p, *bufcln;
    int fd;
    struct stat st;
    struct dirent de;

    if((fd = open(path, 0)) < 0){
        fprintf(2, "find: cannot open %s\n", path);
        exit(1);
    }
    if(fstat(fd, &st) < 0){
        fprintf(2, "find: cannot stat %s\n", path);
        close(fd);
        exit(1);
    }
    if(st.type == 1){
        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;
            }
            switch(st.type){
                case T_FILE:
                    if(!strcmp(name, de.name))
                        printf("%s\n", buf);
                    break;
                case T_DIR:
                    if( !(strcmp(de.name, ".") && strcmp(de.name, "..")) )
                        continue;
                    find(buf, name);
                    break;
                default:
                    break;
            }
            for(
                bufcln = buf + strlen(buf);
                bufcln >= buf && *bufcln != '/';
                bufcln--
            );
        }
    }
}

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.

1
2
3
$ echo hello too | xargs echo bye
bye hello too
$
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include "kernel/types.h"
#include "user/user.h"
#include "kernel/param.h"

int main(int argc, char* argv[])
{
    char *au[MAXARG];
    char argu[MAXARG][64];
    char tmp;
    int i = 0, flag = 1;

    for(i = 2; i < argc && flag < MAXARG; i++){
        memcpy(argu[flag], argv[i], strlen(argv[i]));
        flag++;
    }
    i = 0;

    while(read(0,&tmp,1)){
        switch (tmp){
            case ' ':
            case '\n':
                flag++;
                i = 0;
                continue;
            default:
                break;
        }
        if(i < 64)
            argu[flag][i] = tmp;
        else{
            fprintf(2,"xargs: long argument\n");
            exit(1);
        }
        i++;
    }

    for(i = 0; i <= flag; i++)
        au[i] = argu[i];

    if(fork() == 0){
        exec(argv[1], au);
        fprintf(2,"xargs: exec failed\n");
        exit(1);
    }
    wait(0);
    exit(0);
}