6.s081 lab1
文档:
课程介绍 · 6.S081 All-In-One (dgs.zone)
网课:6.S081 / Fall 2020 [麻省理工操作系统 - 2020 年秋季][中英文字幕]_哔哩哔哩_bilibili
1.sleep
main的第一个参数一般是函数名,第二个才是参数
而输入的参数是Ascii码,系统调用sleep需要的是数值,因此需要转换
#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
int 
main(int argc, char *argv[]) 
{
  if (argc != 2) {
    fprintf(2, "Usage: sleep <number>n");
    exit(1);
  }
  int i = *argv[1] - '1';
  sleep(i);
  exit(0);
}
2.pingpong
考验对管道的理解
错误:第一次写的时候,不知道pipe(p1)后,p1[0]为读入端,p1[1]为写入端。也就是说p1[0]、p1[1]的分工是被定死了的
这里close是一种习惯,当一个进程有太多管道的时候,可能会爆掉。比如xv6的每个进程最多只能打开16个文件描述符
read(p1[0], buf, n) 是从管道p1[0]中读取n个字节到buf,并返回实际读取的字节数。
因此可以使用 read(p1[0], buf, n) == n 来判断是否顺利读入
write(p1[1], buf, n) 同理
#include "kernel/types.h" #include "kernel/stat.h" #include "user/user.h" int main(int argc, char *argv[]){ if(argc > 1){ fprintf(2, "Usage: pingpongn"); exit(1); } int p1[2], p2[2]; pipe(p1); pipe(p2); char buf[1]; if(fork() == 0){ //son should read buf[0] = '0'; close(p1[0]); close(p2[1]); if(read(p2[0], buf, 1) == 1){ close(p2[0]); printf("%d: received pongn", getpid()); } write(p1[1], buf, 1); close(p1[1]); } else{ buf[0] = '1'; close(p1[1]); close(p2[0]); write(p2[1], buf, 1); close(p2[1]); if(read(p1[0], buf, 1) == 1){ close(p1[0]); printf("%d: received pingn",getpid()); } } exit(0); }


3. primes
错误:把函数定义在main()之后,导致编译出错
main()函数进行第一次fork,父进程通过管道向子进程传递2~35。子进程调用递归。
递归的第一件事是检查其父进程是否通过管道传递数字,如果没有,说明递归结束。
如果有,那么传递的第一个数字i一定是质数(这些数都是不能被比它小的数字整除的),将其打印。
然后进行fork(),本进程进行筛选,将不能被i整除的数字传递给子进程,子进程调用递归
进程1->进程2: 传递 2~35
进程2:打印2,进程2->进程3 传递: 3~35 筛掉能被2整除的数,传递给进程3
进程3:打印3,进程3->进程4 传递: 5~35(不能被2、3整除) 筛掉能被3整除的数,传递给4
#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
void ff(int p[]){
	close(p[1]);
	int i;
	// finish 2~35
	if(read(p[0], &i, sizeof(i)) == 0){
		close(p[0]);
		exit(0);
	}
	printf("prime %dn",i);
	int num, newp[2];
	pipe(newp);
	//son recursion
	if(fork() == 0){
		close(p[0]);
		close(newp[1]);
		ff(newp);
	}
	//parent output for son
	else{
		close(newp[0]);
		// get digit from its parent
		while(read(p[0], &num, sizeof(num)) != 0){
			//sift digit, and send to son
			if(num % i != 0)
				write(newp[1], &num, sizeof(num)); 
		}
		close(p[0]);
		close(newp[1]);
		wait(0);
	}
	exit(0);
}
int main(int argc, char *argv[]){
	//need not input
	if(argc > 1){          
		fprintf(2, "Usage: primesn");
		exit(1);
	}
	int p[2];
	pipe(p);
	
	//son
	if(fork() == 0){
		close(p[1]);
		ff(p);
	}
	//parent
	else{
		close(p[0]);
		for(int i = 2; i <= 35; i++){
			write(p[1], &i, sizeof(i));
		}
		close(p[1]);
		wait(0);
	}
	exit(0);
}
4. find
错误:
在把目录名加入到buf后面的时候,一开始没想到用p,写成
buf[strlen(buf)] = '/';
memmove(buf + strlen(buf), de.name, DIRSIZ);
buf[ strlen(buf) ] = 0;
这是因为没有想清楚,这是个dfs,while中的每个文件名相当于多叉树的一个分叉,走出去一步后应该撤销,再走另一分叉。buf[ strlen(buf) ] = 0;显然只是在结尾加个0,buf会成为当前目录下所有文件名的拼接。path name1 name2 name3
应该使用p记录当前结点的path,一次循环结束后,memove把name2复制到当前path之后,而不是name1之后。然后再加0,这样即使name1很长,也因为加了0不影响
p指向'/'后一位 path/aaaaaaaa
memove(p, de.name, strlen(de.name)) path/bbbaaaaa
p[strlen(de.name)]=0 path/bbb0aaaa
主要的问题是对很多全局变量不清楚
struct stat st; fstat(fd, &st) 是将fd的信息存到结构体st中
struct dirent de;
while(read(fd, &de, sizeof(de)) == sizeof(de)) 是遍历fd下的每个文件, 将fd中的某个文件读入到结构体de。de.name是文件名
stat的type属性:T_FILE为文件,T_DIR为目录
疑问:open(path, 0)的path是整个读进去,还是读到0为止
思路:dfs
#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
#include "kernel/fs.h"
void find(char *path, char *target){
	char buf[256], *p;
	int fd;
	struct dirent de;
	struct stat st;
	//打开path
	if((fd = open(path, 0)) < 0){
		fprintf(2, "find: cannot open %sn", path);
		return;
	}
	// 调用 fstat 将 fd 对应的文件信息记录在 st 中
	if(fstat(fd, &st) < 0){
		fprintf(2, "find: cannot stat %sn", path);
		return;
	}
	
	switch(st.type){
	// st.type 为文件时直接返回即可
	case T_FILE:
		if(strcmp(path + strlen(path) - strlen(target), target) == 0){
			printf("%sn", path);
		}
		break;
    //若为目录,则使用DFS,遍历当前目录下的每一个文件或目录,调用find不断递归,直到找到target
	case T_DIR:
		if(strlen(path) + 1 + DIRSIZ + 1 > sizeof buf){
			printf("find: path too longn");
			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, ".") == 0 || strcmp(de.name, "..") == 0)
				continue;
            // 将 de.name 拷贝到 p 中
			memmove(p, de.name, strlen(de.name));
            //设置路径的结束符,因为buf要递归传给下一步作为path
			p[strlen(de.name)] = 0;
			find(buf, target);
		}
		break;
	}
	close(fd);
}
int main(int argc, char *argv[]){
	if(argc < 3){
		exit(0);
	}
	char target[256];
//自动在输入的目标前加一个‘/’
	target[0] = '/';
	strcpy(target + 1, argv[2]);
	find(argv[1], target);
	exit(0);
}