6.1810-utils

本文最后更新于:2024年3月4日 晚上

算是寒假稍微干的一点正事吧,趁着旅游美赛拜年的空隙试着尝试了一下lab,和jyy的网课配套使用。

课程官网在 https://pdos.csail.mit.edu/6.1810/2023/ , hint和评测都十分用心。

在lab1犯的很蠢的错误就是自己折腾了好久gcc , 试着

1
gcc -I ./ -MMD -c your.c -o your.o

去编译,后来发现大部分时候都不需要这样,直接make就好。

甚至因为在primes里开了无数的线程然后给我的wsl宕机了(逃

boot xv6

照着做就可以喽qwq

sleep

有现成的系统调用可以用,照着提示配好存根,开睡!

1
sleep(atoi(argv[1]));

pingpong

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
int
main(int argc, char *argv[])
{
if(argc != 1){
fprintf(2, "Usage: pingpong");
exit(1);
}
int p1[2];
int p2[2];
pipe(p1);
pipe(p2);
char buf1[4];
char buf2[4];
memset(buf1,0,sizeof(buf1));
memset(buf2,0,sizeof(buf2));
if (fork() == 0) {
write(p1[1],"ping",4);
read(p2[0],buf1,4);
fprintf(2,"%d: received %s\n",getpid(),buf1);
} else {
read(p1[0],buf2,4);
fprintf(2,"%d: received %s\n",getpid(),buf2);
write(p2[1],"pong",4);
}
sleep(5);
exit(0);
}

回头写blog的时候发现自己写的好烂啊,比如内存空间会被fork复制所以不需要这么多buf,比如sleep不如wait,总之过了。

如果既不sleep也不wait的话主线程提前结束会先输出下一个命令提示符$.

primes

是一个很符合直觉的筛,但是写起来有点坑(

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
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
void cal(int p[])
{
int write_p[2];
pipe(write_p);
int i = 0;
int num;
int status = read(p[0], &num, sizeof(num));
if (status == 0)
{
close(p[1]);
close(write_p[1]);
close(write_p[0]);
exit(0);
}
int pid = fork();
if (pid < 0)
{
exit(1);
}
if (pid == 0)
{
close(write_p[1]);
cal(write_p);
}
else
{
for (;;)
{
int firstnum;
if (status == 0){
close(p[1]);
close(p[0]);
close(write_p[1]);
exit(0);
}
else if (i == 0)
{
firstnum = num;
printf("prime %d\n", firstnum);
}
else
{
if ((num % firstnum) != 0)
{
write(write_p[1], &num, sizeof(num));
}
}
i++;
status = read(p[0], &num, sizeof(num));
}
}
wait(0);
exit(0);
}

int main(int argc, char *argv[])
{
if (argc != 1)
{
fprintf(2, "Usage: primes");
exit(1);
}
int p[2];
pipe(p);
int pid = fork();
if (pid < 0)
{
exit(1);
}
if (pid == 0)
{
close(p[1]);
cal(p);
}
else
{
for (int i = 2; i < 35; i++)
{
write(p[1], &i, sizeof(i));
}
close(p[1]);
}
wait(0);
exit(0);
}

重要的hint就是read returns zero when the write-side of a pipe is closed.
所以需要判断是否读出0。

另一点是fork了以后fd同样被复制了一份,所以在pipe用完以后要在父子进程中都关闭fd。

find

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
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
int my_strncmp(const char *s1, const char *s2, int n)
{
for (int i = 0; i < n; i++)
{

if (s1[i] != s2[i] || s1[i] == '\0' || s2[i] == '\0')
{
return (unsigned char)s1[i] - (unsigned char)s2[i];
}
}
return 0;
}

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

if ((fd = open(path, O_RDONLY)) < 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 (mode == 1)
{
uint l1 = strlen(name);
uint l2 = strlen(path);
if (l2 >= l1)
{
if (my_strncmp(path + l2 - l1, name, l1) == 0)
{
printf("%s\n", path);
}
}
} else {
printf("%s\n", path);
}
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;
if (!strcmp(de.name, ".") || !strcmp(de.name, ".."))
continue;
memmove(p, de.name, DIRSIZ);
p[DIRSIZ] = 0;
if (stat(buf, &st) < 0)
{
printf("find: cannot stat %s\n", buf);
continue;
}
find_name(buf, name, mode);
*p = 0;
}
break;
}
close(fd);
}

int main(int argc, char *argv[])
{
if (argc == 1)
{
find_name(".", "", 0);
}
if (argc == 2) // only path no name
{
find_name(argv[1], "", 0);
}
if (argc == 3) // path and name
{
find_name(argv[1], argv[2], 1);
}
exit(0);
}

通过维护一个buffer和p来记录当前的路径,对DIR里读出的特殊的.和..特判一下就好

xargs

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
#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"

#define MAXARG 10

int main(int argc, char *argv[])
{
char buf[512];
char *cmd[MAXARG];

if (argc < 2)
{
fprintf(2, "Usage: xargs command\n");
exit(1);
}

for (int i = 1; i < argc; i++)
{
cmd[i - 1] = argv[i];
}
int fd = 0;
char *p;
while (1)
{
p = buf;
int n = 0;
while (1)
{
if (read(fd, p, 1) != 1)
{
*p = 0;
break;
}
if (*p == '\n' || *p == '\r')
{
*p = 0;
break;
}
if (++n >= sizeof(buf))
{
fprintf(2, "xargs: line too long\n");
exit(1);
}
p++;
}

if (n == 0)
{
break;
}

if (fork() == 0)
{
cmd[argc - 1] = buf;
cmd[argc] = 0;
exec(cmd[0], cmd);
fprintf(2, "exec %s failed\n", cmd[0]);
exit(1);
}
else
{
wait(0);
}
}
exit(0);
}

一个exec教学(?

感觉jyy老师讲的很好,exec就是替换状态机(


6.1810-utils
http://tzr.icu/20240304/6-1810-utils/
发布于
2024年3月4日
更新于
2024年3月4日
许可协议