该实验主要用来熟悉xv6以及其系统调用
tips:
实验目的:
实验目的:
实验代码:
#include "kernel/types.h"
#include "user/user.h"
int
main(int argc, char *argv[]){
int num;
if(argc != 2){
fprintf(2, "sleep must have 1 parameters!\n");
exit(1);
}
num = atoi(argv[1]);
printf("(nothing happens for a little while)\n");
sleep(num);
exit(0);
}
实验要求:
实验代码:
#include "kernel/types.h"
#include "user/user.h"
int
main(int argc, char *argv[]){
char msg = 'm';
int length = sizeof(msg);
int p1[2]; //父-->子
int p2[2]; //子-->父
pipe(p1);
pipe(p2);
if(fork() == 0){
close(p1[1]); //关闭父到子的管道写口
close(p2[0]); //关闭子到父的管带读口
//子进程
if(read(p1[0], &msg, length) != length){
printf("child read parent msg error\n");
exit(1);
}
printf("%d: received ping\n", getpid());
if(write(p2[1], &msg, length) != length){
printf("child send msg to parent error\n");
exit(1);
}
exit(0);
}
close(p1[0]);
close(p2[1]);
if(write(p1[1], &msg, length) != length){
printf("parent send msg to child error\n");
exit(1);
}
if(read(p2[0], &msg, length) != length){
printf("parent read child msg error\n");
exit(1);
}
printf("%d: received pong\n", getpid());
//wait(0); //不关心子进程的退出状态
exit(0);
}
实验要求:
实验代码:
#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
//素数判断使用素数表法,即当前的素数除以比他小的素数均不能整除
//如果一个数不能整除比它小的任何素数,那么这个数就是素数
//思想,素数 2 - 35 依次通过 pipe 流经各个线程,每个线程判断出第一个素数之后,从该数开始往下流
//每个线程都除以当前的cur_prime,并更新cur_prime,这样子每个线程只需要做一次除法即可
//因为传递到当前线程的所有输入都已经除过 cur_prime 之前的所有素数了(即类似于层层过滤)
int input[34]; //存储2到35
int cur_prime = 1; //当前要被除的素数
/**
可以简单实现为了一个基于pipe的并行处理框架
stream类型的为操作pipeline,每个元素都需要经过流水线操作
pipe则为元素pipeline,每个元素一个线程去单独处理,pipeline用于切分元素
因此需要一个切分元素的规则
*/
//检查元素是否符合要求
int check_elem(int elem);
//更新检查条件
void update_check(int elem);
//处理检查合格的元素
void process_elem(int elem);
void exec_pipeline(int pipe_rfd);
void init_pipeline(int len){
int i = 0;
//初始化输入
for(i = 0; i < len; i++){
input[i] = i + 2;
}
cur_prime = 1;
//printf("[debug]init input done\n");
}
void start_pipeline(int* input, int len){
int i = 0;
int temp;
int fd[2];
int end = -1;
pipe(fd);
for(; i < len; i++){
//向pipeline输入元素
temp = input[i];
write(fd[1], (char*)(&temp), 4);
}
write(fd[1], (char*)&end, 4);
//启动子进程
if(fork() == 0){
exec_pipeline(fd[0]);
} else {
//父进程关闭读口
close(fd[0]);
close(fd[1]);
}
//等待子进程结束
wait(0);
exit(0);
}
//参数为上一个进程创建的pipe的读口
//先读后写
void exec_pipeline(int pipe_rfd){
int temp;
char buf[4];
int end = -1; //结束符
int fd[2];
int elems = 0;
pipe(fd);
while(1){
if(read(pipe_rfd, buf, 4) == 0){
continue;
}
// 读取元素
temp = *((int *)buf);
//printf("[debug] child %d read elem:%d\n", getpid(), temp);
// 如果为结束符,则跳出循环
if(temp == -1){
//printf("[debug] child %d read end\n", getpid());
break;
}
// 检查元素是否合法
if(!check_elem(temp)){
//printf("[debug] child %d ignore %d\n", getpid(),temp);
continue;
}
//第一个符合要求的元素,输出
if(elems == 0){
//确保每次分割,可以选择一次更新切分条件
update_check(temp);
process_elem(temp);
elems = 1;
continue;
}
//第二个符合要求的元素,输送给下一个进程
if(elems > 0){
//printf("[debug] child %d write elem:%d\n", getpid(), temp);
write(fd[1], (char*)&temp, 4);
elems++;
}
}
close(pipe_rfd);
if(elems > 1){
// 如果有向子进程输送元素,则写结束符
write(fd[1], (char*)&end, 4);
}
//printf("[debug] child %d exit\n", getpid());
if(elems > 1 && fork() == 0){
exec_pipeline(fd[0]);
}
close(fd[1]);
close(fd[0]);
wait(0);
exit(0);
}
int main(){
init_pipeline(34);
start_pipeline(input, 34);
exit(0);
}
int check_elem(int elem){
if(elem == 2){
return 1;
}
if(elem % cur_prime == 0){
//可以整除
return 0;
}
// 不可以整除,只更新一次素数数组,防止在一个进程中就把所有的素数都算出来了,平摊计算成本
// 即第一个进程只计算 1,2 之后的第一个素数,其他数只能不能被2整除就过关
return 1;
}
void update_check(int elem){
cur_prime = elem;
}
void process_elem(int elem){
printf("prime %d\n", elem);
}
方案二:
#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
//素数判断使用素数表法,即当前的素数除以比他小的素数均不能整除
//如果一个数不能整除比它小的任何素数,那么这个数就是素数
//思想,素数 2 - 35 依次通过 pipe 流经各个线程,每个线程判断出第一个素数之后,从该数开始往下流
//每个线程都除以当前的cur_prime,并更新cur_prime,这样子每个线程只需要做一次除法即可
//因为传递到当前线程的所有输入都已经除过 cur_prime 之前的所有素数了(即类似于层层过滤)
int input[34]; //存储2到35
int cur_prime = 1; //当前要被除的素数
/**
可以简单实现为了一个基于pipe的并行处理框架
stream类型的为操作pipeline,每个元素都需要经过流水线操作
pipe则为元素pipeline,每个元素一个线程去单独处理,pipeline用于切分元素
因此需要一个切分元素的规则
*/
//检查元素是否符合要求
int check_elem(int elem);
//更新检查条件
void update_check(int elem);
//处理检查合格的元素
void process_elem(int elem);
void exec_pipeline(int pipe_rfd);
void init_pipeline(int len){
int i = 0;
//初始化输入
for(i = 0; i < len; i++){
input[i] = i + 2;
}
cur_prime = 1;
//printf("[debug]init input done\n");
}
void start_pipeline(int* input, int len){
int i = 0;
int temp;
int fd[2];
int end = -1;
pipe(fd);
for(; i < len; i++){
//向pipeline输入元素
temp = input[i];
write(fd[1], (char*)(&temp), 4);
}
write(fd[1], (char*)&end, 4);
//启动子进程
if(fork() == 0){
exec_pipeline(fd[0]);
} else {
//父进程关闭读口
close(fd[0]);
close(fd[1]);
}
//等待子进程结束
wait(0);
exit(0);
}
//参数为上一个进程创建的pipe的读口
//先读后写
void exec_pipeline(int pipe_rfd){
int i = 3;
int temp;
char buf[4];
int end = -1; //结束符
int fd[2];
int elems = 0; //记录当前进程通过检查的elem个数
//由于xv6打开文件限制,在此处关闭之前从父进程继承来的无用的fd
for(; i < pipe_rfd; i++){
close(i);
}
pipe(fd);
while(1){
if(read(pipe_rfd, buf, 4) == 0){
continue;
}
//printf("fds:%d,%d,%d\n", pipe_rfd, fd[0], fd[1]);
// 读取元素
temp = *((int *)buf);
//printf("[debug] child %d read elem:%d\n", getpid(), temp);
// 如果为结束符,则跳出循环
if(temp == -1){
//printf("[debug] child %d read end\n", getpid());
break;
}
// 检查元素是否合法
if(!check_elem(temp)){
//printf("[debug] child %d ignore %d\n", getpid(),temp);
continue;
}
//第一个符合要求的元素,输出
if(elems == 0){
//确保每次分割,可以选择一次更新切分条件
update_check(temp);
process_elem(temp);
elems = 1;
continue;
}
//第二个符合要求的元素,输送给下一个进程
if(elems > 0){
//printf("[debug] child %d write elem:%d\n", getpid(), temp);
write(fd[1], (char*)&temp, 4);
// 创建子进程,进行下一个阶段的处理
if(elems == 1){
// 有元素输送给下一个阶段,创建新的子进程
if(fork() == 0){
exec_pipeline(fd[0]);
}
}
elems++;
}
}
close(pipe_rfd);
if(elems > 1){
// 如果有向子进程输送元素,则写结束符
write(fd[1], (char*)&end, 4);
}
//printf("[debug] child %d exit\n", getpid());
close(fd[1]);
close(fd[0]);
wait(0);
exit(0);
}
int main(){
init_pipeline(34);
start_pipeline(input, 34);
exit(0);
}
int check_elem(int elem){
if(elem == 2){
return 1;
}
if(elem % cur_prime == 0){
//可以整除
return 0;
}
// 不可以整除,只更新一次素数数组,防止在一个进程中就把所有的素数都算出来了,平摊计算成本
// 即第一个进程只计算 1,2 之后的第一个素数,其他数只能不能被2整除就过关
return 1;
}
void update_check(int elem){
cur_prime = elem;
}
void process_elem(int elem){
printf("prime %d\n", elem);
}
参考:
#include "kernel/types.h"
#include "user/user.h"
void find_prime(int *input, int num){
if(num == 1){
printf("prime %d\n", *input);
return;
}
int p[2],i;
int prime = *input;
int temp;
printf("prime %d\n", prime);
pipe(p);
for(i = 0; i < num; i++){
temp = *(input + i);
write(p[1], (char *)(&temp), 4);
}
close(p[1]);
// 父进程没有关闭pipe[0]
if(fork() == 0){
int counter = 0;
char buffer[4];
while(read(p[0], buffer, 4) != 0){
temp = *((int *)buffer);
if(temp % prime != 0){
*input = temp;
input += 1;
counter++;
}
}
find_prime(input - counter, counter);
exit(0);
}
wait(0);
}
int main(){
int input[34];
int i = 0;
for(; i < 34; i++){
input[i] = i+2;
}
find_prime(input, 34);
exit(0);
}
实验要求:
. 和 ..
目录实验代码:
#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
#include "kernel/fs.h"
void find(char* path, char* name);
int
main(int argc, char *argv[])
{
if(argc < 2){
printf("args must have path and name\n");
exit(0);
}
char* path = argv[1];
char* filename = argv[2];
find(path, filename);
exit(0);
}
void find(char* path, char* name){
int fd;
struct dirent de;
struct stat st;
char buf[512], *p; //buf存储路径,p指向路径的末尾
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_DEVICE:
case T_FILE:
fprintf(2, "find: %s is not a path\n", path);
close(fd);
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++ = '/'; // path ---> path/
//读取每个目录项
while(read(fd, &de, sizeof(de)) == sizeof(de)){
if(de.inum == 0)
continue;
//需要去除 .和 ..
if(strcmp(de.name, ".") == 0 || strcmp(de.name, "..") == 0){
//printf("find: file %s\n", de.name);
continue;
}
// 拼接路径 path/filename
memmove(p, de.name, DIRSIZ);
p[DIRSIZ] = '\0'; //添加结束符
//读取文件的具体信息
if(stat(buf, &st) < 0){
printf("find: cannot stat %s\n", buf);
continue;
}
//printf("xxx:%s, %d\n", buf, st.type);
if(st.type == T_FILE || st.type == T_DEVICE){
//如果文件名相同
if(strcmp(name, de.name) == 0){
printf("%s\n", buf);
}
} else {
//是目录,递归查询
find(buf, name);
}
}
close(fd);
break;
}
}
实验要求:
实验代码:
#include "kernel/types.h"
#include "user/user.h"
#include "kernel/param.h"
int main(int argc, char *argv[]){
int i;
int cmd_len = 0;
int buf_len;
char buf[32];
char *cmd[MAXARG];
//读取 xargs 后面的参数,即最终要执行的命令
for(i = 1; i < argc; i++){
cmd[cmd_len++] = argv[i];
}
//read读取管道的输出,即面前的命令的执行结果,并进行处理
while((buf_len = read(0, buf, sizeof(buf))) > 0){
char xargs[32] = {"\0"}; //追加参数
cmd[cmd_len] = xargs;
for(i = 0; i < buf_len; i++){
if(buf[i] == '\n'){
if(fork() == 0){
exec(argv[1], cmd);
}
wait(0);
} else {
xargs[i] = buf[i];
}
}
}
exit(0);
}