Lab util Unix utilities

​ ucore写了以后算是对操作系统有一个初步的认识,ucore 既然也是参照 xv6 来的,那何尝不尝试一下这个呢,而且这个课程可以对标更多的其他课程,坑也会少很多的样子,抓紧时间学习吧;

​ 先说一下整体的步骤:

因为有了 OS 基础、而不是第一次学习 OS,所以就比较快了可能,但是会发现让自己去独立的写一个.c文件而不是像ucore那样去填空还是有点儿吃力的

​ 1、看xv6电子书要求章节,看PPT,看说明

​ 2、看每个实验要求要看的源码

​ 3、写lab、debug

​ 4、不会的地方先查资料,再不会看学长代码提供的思路,最终独立敲一遍

​ 课程网页:https://pdos.csail.mit.edu/6.828/2020/index.html

Lab Util

​ 正式开始之前,得搭建好实验环境,选择国内镜像站最好选择 ustc 的,貌似其他的几个镜像站 Ubuntu 20.04 有的安装包没进行缓存或者丢弃了(eg. qemu的部分组建)

sleep

​ 这个部分要求写一个用户态程序,然后理解用户态是如何通过 system call 调用内核代码的;记录踩坑经历,include 部分的每个顺序是有要求的,去查看三个头文件会发现会有依赖关系,如果顺序错了会造成编译失败,至于为啥请查询 C 语法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/// order is important

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

int
main(int argc,char* argv[])
{
if(argc<2){
fprintf(2,"Sleep Error: Argument is Needed...\n");
exit(1);
}

int n = atoi(argv[1]);
sleep(n);
exit(0);
}

pingpong

​ 通过管道实现两个进程之间的通讯,子进程向父进程写一个字节,父进程也向子进程写一个字节,分别起两个管道就好了;我是直接输出字符串,没进行检测,想的是如果出错的化 read 会阻塞啥的,逻辑正确就没管了

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
/// order is important

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

int
main()
{
int p1[2];
int p2[2];
pipe(p1);
pipe(p2);
char buf[1];

// fd[0] read end,fd[1] write end

if(fork() == 0){
write(p2[1],"c",1);
close(p2[0]);

read(p1[0],buf,1);
printf("%d: received ping\n",getpid());
close(p1[1]);

exit(0);
}else{
write(p1[1],"f",1);
close(p1[0]);
wait(0);

read(p2[0],buf,1);
printf("%d: received pong\n",getpid());
close(p2[1]);
exit(0);
}
}

primes

​ 通过管道,实现一个流水线,也就是CSP模型的管道解(http://swtch.com/~rsc/thread/),卡了很久很久,因为不会写“共享”(这里的共享意思是每个进程都会执行的相同代码)部分的代码,只会写流水线长度为 2 的情况,想了很久想到用 goto 可以,而且书上给了一个 dup 的例子来进行文件描述符的控制,这样就避免了题干中提到的坑了

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
/// order is important

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


void redict(int fd[]) {
close(0);
close(fd[1]);
dup(fd[0]);
close(fd[0]);
}

int main() {
int fd[2];
pipe(fd);

if (fork() == 0) {
redict(fd);

int buf, n, x, fd1[2];
lable:
if ((n = read(0, &buf, sizeof(int)) <= 0 || buf <= 0)) {
close(0);
exit(0);
}
printf("prime %d\n", buf);
x = buf;

pipe(fd1);

if (fork() == 0) {
redict(fd1);
goto lable;
}

while (read(0, &buf, sizeof(int)) > 0) {
if (buf % x != 0) {
write(fd1[1], &buf, sizeof(int));
}
}
close(0);
close(fd1[1]);
wait(0);
exit(0);
} else {
for (int i = 2; i <= 35; i++) {
write(fd[1], &i, sizeof(int));
}
close(fd[1]);
wait(0);
}
exit(0);
}

find

​ find这个主要是引入了几个结构体和函数,需要仔细的阅读 ls.c 文件来弄懂每个函数是干什么的,然后才可以进行代码否则的话就会一直卡着;其实递归还好拉,就检测当前文件夹下边儿读到的一个stat结构体类型,如果是文件就判断名字是否相同,如果是文件夹就递归下去就好了(.和..的情况不进行递归),微光招新题也有一道类似的,实现copy函数

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

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

if ((fd = open(filepath, 0)) < 0) {
printf("find: cannot open %s\n", filepath);
return;
}

if (fstat(fd, &st) < 0) {
printf("find: cannot stat %s\n", filepath);
close(fd);
return;
}

if (st.type != T_DIR) {
printf("find: cannot find file %s in filepath %s\n", filename, filepath);
return;
}

if(strlen(filepath) + 1 + DIRSIZ + 1 > sizeof buf){
printf("find: path too long\n");
return;
}
strcpy(buf, filepath);
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;
}

if (strcmp(de.name, ".") == 0 || strcmp(de.name, "..")==0) {
continue;
}
switch (st.type) {
case T_FILE:
if (strcmp(p, filename) == 0) {
printf("%s\n", buf);
}
break;
case T_DIR:
find(buf, filename);
break;
default:
break;
}
// close(fd);
}
}

int
main(int argc, char *argv[]) {
if (argc < 2) {
printf("find error: need at least two arguments 'filepath' and 'filename'\n");
exit(0);
}
find(argv[1], argv[2]);
exit(0);
}

xargs

​ 这道题我一开始没理解到题目意思,我以为要写一个和 unix 一模一样的出来,一下子给我整懵了,当时也不是不可以写,但是仔细读题干发现要求完全不同好吧,xargs 后边儿执行的内容除了 exe_args 的以外,其他的是从标准输入进行输入的,那这样就好写很多阿,保存好 xargs 后边儿执行的命令,默认每次执行一次,只需要吧前边儿的内容嵌近来就 ok

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

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

if (argc < 2) {
printf("xargs error: need at least 2 arguments\n");
exit(0);
}

/// To get the xargs command args
/// We need not to make the optimizations for xargs -n 1 echo line the fot the choice -n 1
/// its always -n 1 for this lab
char *exec_args[MAXARG];
char buf[512];
int cnt = 0;

for (int i = 1; i < argc; ++i) {
exec_args[cnt] = (char *) malloc(20);
memmove(exec_args[cnt], argv[i], strlen(argv[i]));
cnt++;
}

exec_args[cnt] = (char *) malloc(20);
int len = read(0, buf, sizeof(buf));
int start = 0;

for (int i = 0; i < len; i++) {
if (buf[i] == '\n') {
memset(exec_args[cnt], 0, 20);
memmove(exec_args[cnt], buf + start, i - start);
exec_args[cnt + 1] = (char *) 0;
start = i + 1;
if (fork() == 0) {
exec(*exec_args, exec_args);
} else {
wait(0);
}
}
}
exit(0);
}

time

​ 写一个time.txt的文件,里边儿写好完成实验花的时间,那每天2小时,一周完成14h吧差不多,太菜了我还是,呜呜呜~~

​ make grade 总算完成了,还是最简单的实验了应该是,下周lab1哇


Lab util Unix utilities
https://www.bencorn.com/2021/03/21/Lab-util-Unix-utilities/
作者
Bencorn
发布于
2021年3月21日
许可协议