MIT 6.s081课程实验 Lab1

编程入门 行业动态 更新时间:2024-10-25 06:22:17

MIT 6.s081<a href=https://www.elefans.com/category/jswz/34/1770049.html style=课程实验 Lab1"/>

MIT 6.s081课程实验 Lab1

Lab1
Lab1实现几个简单函数,目的是促进我们对xv6这个小系统的了解

sleep

  1. 在/user文件夹中添加sleep.c文件如下,主要工作是解析参数->调用sleep的系统调用
  2. 在Makefile文件的UPROGS中仿照其他功能添加_sleep选项,这样就能在shell中使用sleep方法
  3. 测试:运行make qemu后,在shell中运行sleep x,就会阻塞x秒,不过什么都不会发生
#include "kernel/types.h"
#include "user/user.h"int
main(int argc, char *argv[]){if(argc != 2){fprintf(2, "Usage: sleep sleep_time\n");exit(1);}int sleep_time = atoi(argv[1]);sleep(sleep_time);exit(0);
}

ping pong

此小实验使用匿名管道pipe进行父子进程通信,管道是半双工通信方法,要实现父子进程信息的相互传输,则需要2个管道,每个管道负责1个方向的信息传输,下标为0表示读端,1表示写端。

#include "kernel/types.h"
#include "user/user.h"
int main(int argc, char *argv[]){int p_child_to_parent[2];int p_parent_to_child[2];//0: read 1: writepipe(p_child_to_parent);pipe(p_parent_to_child);if(fork() == 0){ //child processprintf("%d: received ping\n", getpid());char ch;close(p_parent_to_child[1]);close(p_child_to_parent[0]);read(p_parent_to_child[0], &ch, 1);close(p_parent_to_child[0]);write(p_child_to_parent[1], &ch, 1);close(p_child_to_parent[1]);exit(0);} else{char ch = 'z';close(p_child_to_parent[1]);close(p_parent_to_child[0]);write(p_parent_to_child[1], &ch, 1);close(p_parent_to_child[1]);wait(0);read(p_child_to_parent[0], &ch, 1);close(p_child_to_parent[0]);printf("%d: received pong\n", getpid());}exit(0);
}

问题(闲暇时查看)

父子进程为什么共享管道的文件描述符?
为什么要关闭不需要的文件描述符,不关闭会有什么问题?
管道读写方法是阻塞的还是非阻塞的?
阻塞指的是什么?

primes

使用管道和多进程实现了一个简单的线性筛。对于每个素数,进行打印后,为其创建1个管道,只有与此素数互质的数才能“流进“此管道。注意需要wait子进程以回收其资源,并且才能确保所有进程都运行结束,主进程才结束。

#include "kernel/types.h"
#include "user/user.h"
void get_primes(int *from_pipe){close(from_pipe[1]);// 'read' returns zero when the write-side of a pipe is closed.int cur_prime;if (read(from_pipe[0], &cur_prime, 4) == 0){close(from_pipe[0]);exit(0);}printf("prime %d\n", cur_prime);int num;int to_pipe[2];pipe(to_pipe);if  (fork() == 0) {get_primes(to_pipe);} else {close(to_pipe[0]);while (read(from_pipe[0], &num, 4)){if (num % cur_prime){write(to_pipe[1], &num, 4);}}close(from_pipe[0]);close(to_pipe[1]);wait(0); // 若不等待子进程结束,shell提前停止}
}
int main(int argc, char *argv[]){int p[2];pipe(p);if(fork() == 0){ //子孙进程get_primes(p);} else{ //主进程close(p[0]);for(int i = 2; i <= 35; i ++) write(p[1], &i, 4);close(p[1]);wait(0);}exit(0);
}

小小知识点

若read出错,则返回值为-1,否则返回值是读取的字节数,因此若返回0,说明管道已经读取完毕,即写端已经关闭。

find

递归地查找某个文件的路径。可参考ls.c是如何实现的,思路是:

  1. 使用fstat系统调用获得打开文件路径后的文件描述符fd对应的stat,用于描述文件的信息,其定义如下:

    struct stat {int dev;     // File system's disk deviceuint ino;    // Inode numbershort type;  // Type of fileshort nlink; // Number of links to fileuint64 size; // Size of file in bytes
    };
    
  2. 根据stat的type,若type是T_FILE,表示普通文件,则对比此路径的文件名是否和目标文件名相同,相同则直接输出完整路径;若type为T_DIR,则使用递归地读取此目录的内容,目录中存放的是子目录或者子文件的目录项,目录项的数据结构如下,利用name继续往下递归。

    struct dirent {ushort inum;char name[DIRSIZ];
    };
    

通过这个小实验,我们初步了解了操作系统的文件系统构成,文件包括普通文件/设备/目录,每个文件都有1个目录项,目录项中存放其路径和inum,inum其实是文件inode的下标,inode是每个文件的唯一索引,其定义如下,用来存储文件的元数据信息,如ref引用计数,表示有多少个文件描述符指向此文件;valid表示此文件是否已经从磁盘加载到内存中等等。

// in-memory copy of an inode
struct inode {uint dev;           // Device numberuint inum;          // Inode numberint ref;            // Reference countstruct sleeplock lock; // protects everything below hereint valid;          // inode has been read from disk?short type;         // copy of disk inodeshort major;short minor;short nlink;uint size;uint addrs[NDIRECT+1];
};

完整代码:

#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
#include "kernel/fs.h"
char*
fmtname(char *path)
{static char buf[DIRSIZ+1];char *p;// Find first character after last slash.for(p=path+strlen(path); p >= path && *p != '/'; p--);p++;// Return blank-padded name.if(strlen(p) >= DIRSIZ)return p;memmove(buf, p, strlen(p));buf[strlen(p)] = 0;return buf;
}
void
find(char *path, char *target_file)
{char buf[512], *p;int fd;struct dirent de;struct stat st;if((fd = open(path, 0)) < 0){fprintf(2, "find: cannot open %s\n", path);return;}if(fstat(fd, &st) < 0){fprintf(2, "find: cannot stat %s\n", path);close(fd);return;}switch(st.type){case T_FILE:if(strcmp(fmtname(path), target_file) == 0)printf("%s\n", path);break;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 || strcmp(de.name, ".") == 0 || strcmp(de.name, "..") == 0) continue;memmove(p, de.name, DIRSIZ);p[DIRSIZ] = 0;find(buf, target_file);}break;}close(fd);
}int
main(int argc, char *argv[])
{if(argc != 3){fprintf(2, "Usage: find <dirname> <filename>\n");exit(1);}find(argv[1], argv[2]);exit(0);
}

xargs

题意是说 xargs后面紧跟着一个命令:xargs [command],当然这个命令可能不只一个单词,而是包括多个单词组成的命令,如xargs echo bye。紧接着,从标准输入中逐行为此命令读取附加的参数arg1 arg2 ...,然后执行命令[command] arg1 arg2 ...。对于从标准输入中的每一行,都要执行一次命令。
提示1:可以使用forkexec,即当从标准输入读到一行,则fork出1个子进程去exec该拼接命令;
提示2:可逐个读取字符,当字符为\n则为一行结束标识;但其实参考sh.c,在user/ulib.c中有1个gets函数,可以用来从标准输入中读取一行,至于为什么会想到去sh.c查看参考,是因为sh.c是shell命令,是和标准输入交互最多的模块。
提示3:使用MAXARG来定义1个参数数组。

#include "kernel/types.h"
#include "kernel/param.h"
#include "user/user.h"
#define MAXARGS 10
int main(int argc, char* argv[])
{// 保存可执行命令char* command[MAXARG];for (int i = 1; i < argc; i ++){command[i - 1] = argv[i];}char buf[100];while (gets(buf, 100) && buf[0] != 0) //从标准输入中读取到一行{int argv_idx = argc - 1;//根据空格划分每个参数int len = strlen(buf), start_pos = 0;buf[len] = ' ';for (int i = 0; i <= len; i ++){if (buf[i] == ' '){if (i - start_pos > 1) //有效参数产生{int argv_len = i - start_pos;command[argv_idx] = (char*)malloc(sizeof(char) * argv_len);memset(command[argv_idx], 0, sizeof(command[argv_idx]));memcpy(command[argv_idx], buf + start_pos, argv_len - 1);argv_idx ++;}start_pos = i + 1;}}if (fork() == 0){//将char *[10]强转为char **和exec参数类型匹配exec(command[0], command); //exec的参数是这样不 comand数组最后一个字符串是不是空串for (int i = argc; i < argv_idx; i ++){free(command[i]);}exit(0);}wait(0);}exit(0);
}

总结

实验1是最简单的,让我们先对文件系统,进程通信,系统调用,内存管理这4个部分都有了一定了解,接下来就继续看每个小部分了

更多推荐

MIT 6.s081课程实验 Lab1

本文发布于:2023-12-05 15:46:39,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1664605.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:课程   MIT

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!