6.s081 lab1

Posted 豹豹龙神

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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: pingpong\\n");
		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 pong\\n", 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 ping\\n",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 %d\\n",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: primes\\n");
		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 %s\\n", path);
		return;
	
	// 调用 fstat 将 fd 对应的文件信息记录在 st 中
	if(fstat(fd, &st) < 0)
		fprintf(2, "find: cannot stat %s\\n", path);
		return;
	
	
	switch(st.type)
	// st.type 为文件时直接返回即可
	case T_FILE:
		if(strcmp(path + strlen(path) - strlen(target), target) == 0)
			printf("%s\\n", path);
		
		break;
    //若为目录,则使用DFS,遍历当前目录下的每一个文件或目录,调用find不断递归,直到找到target
	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;
			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);

以上是关于6.s081 lab1的主要内容,如果未能解决你的问题,请参考以下文章

mit6.s081 lab1:Unix Utilities

6.S081-2021-Lab3 Pgtbl学习笔记

6.S081-2021-Lab4 Traps学习笔记

6.S081-2021-lab5 Copy-on-Write Fork

]->Trap与系统调用

MIT6.824-lab1-2022篇(万字推导思路及代码构建)