Xv6启动,lab 1
lab地址:https://pdos.csail.mit.edu/6.S081/2020/labs/util.html
课程地址:https://pdos.csail.mit.edu/6.S081/2020/schedule.html
启动xv6
git clone git://g.csail.mit.edu/xv6-labs-2020
cd xv6-labs-2020
git checkout util
make qemu
退出xv6
回到 monitor 界面:ctrl + a,然后按 c ,即可退出 xv6 的 shell 界面,进入 QEMU 的 monitor 界面,输入 q 按回车即可退出 QEMU。
终止 QEMU 进程:ctrl + a,然后按 x,即可终止 QEMU 进程,回到 Shell 界面。
sleep实验(easy)
在user文件夹下实现sleep.c
实现完成后,需要在Makefile的UPROGS下添加_sleep
,下同。
#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
int
main(int argc, char **argv)
{
if (argc < 2) {
printf("usage: sleep <ticks>\n");
}
sleep(atoi(argv[1]));
exit(0);
}
pingpong实验(easy)
通过两个管道,实现子进程和父进程的交互。
#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
int
main(int argc, char **argv)
{
int pp[2], pc[2];
pipe(pp); // parent => child
pipe(pc); // child => parent
if(fork() == 0) {
// child
char buf;
read(pp[0], &buf, 1);
printf("%d: received ping\n", getpid());
write(pc[1], &buf, 1);
}
else {
// parent
write(pp[1], "!", 1);
char buf;
read(pc[0], &buf, 1);
printf("%d: received pong\n", getpid());
wait(0);
}
exit(0);
}
primes实验(hard)
多进程实现质数筛的方法:
p = get a number from left neighbor
print p
loop:
n = get a number from left neighbor
if (p does not divide n)
send n to right neighbor
注意,每个子进程打开文件描述符的数量是有限的,为16个。而每次fork出的新进程会复制父进程的文件描述符。因此,进程在fork后要及时关闭一定的文件描述符。
另外,设置计算的数字超过200,好像程序就不能正常执行了。
#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
/*
通过管道实现质数筛
*/
void sieve(int left_pipe[2]){
// read and print
int p;
read(left_pipe[0], &p, sizeof(p));
if(p == -1) {
exit(-1);
}
printf("prime %d\n", p);
int right_pipe[2];
pipe(right_pipe);
if(fork() == 0) {
// child process
close(left_pipe[0]);
close(right_pipe[1]);
sieve(right_pipe);
}
else {
// parent process
close(right_pipe[0]); // no need read from right.
int buf;
while(read(left_pipe[0], &buf, sizeof(buf)) && buf != -1) {
if(buf % p == 0) continue;
write(right_pipe[1], &buf, sizeof(buf));
}
buf = -1;
write(right_pipe[1], &buf, sizeof(buf));
wait(0);
}
exit(0);
}
int main(int argc, char **argv) {
int input_pipe[2];
pipe(input_pipe);
if(fork() == 0) {
// child process
close(input_pipe[1]);
sieve(input_pipe);
}
else {
// parent process
close(input_pipe[0]); // no need read
int i;
for(i=2; i<=100; i++) {
write(input_pipe[1], &i, sizeof(i));
}
i = -1;
write(input_pipe[1], &i, sizeof(i));
wait(0);
}
exit(0);
}
find实验(moderate)
find程序。在指定目录中寻找特定的文件。
#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
#include "kernel/fs.h"
void find(char *path, char *target) {
char buf[512], *p;
int fd;
struct dirent de;
struct stat st;
char *cur_dir = "/.";
char *parent_dir = "/..";
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(path + strlen(path) - strlen(target), target) == 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)
continue;
memmove(p, de.name, DIRSIZ);
p[DIRSIZ] = 0;
if(stat(buf, &st) < 0) {
printf("find: cannot stat %s\n", buf);
continue;
}
if(strcmp(buf + strlen(buf) - strlen(cur_dir), cur_dir) == 0)
continue;
if(strcmp(buf + strlen(buf) - strlen(parent_dir), parent_dir) == 0)
continue;
find(buf, target);
}
}
close(fd);
}
int main(int argc, char *argv[]){
if(argc < 3) {
exit(0);
}
find(argv[1], argv[2]);
exit(0);
}
xargs(moderate)
编写xargs工具,用于从标准输入中读入多行信息。然后依次传给xargs后的程序进行执行。
#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
#include "kernel/fs.h"
void run(char *program, char **args) {
// fork 子程序
// 执行每一行的xargs任务
if(fork() == 0) {
exec(program, args);
exit(0);
}
return;
}
int main(int argc, char **argv) {
char buf[2048]; // 读入时使用的内存池。保存标准输入的内容
char *p = buf, *last_p = buf; // p 用于输入,last_p则为当前输入的开头
char *argsbuf[128];
char **args = argsbuf; // 用于每行程序的执行
for(int i=1; i<argc; i++) {
// 后续的 exec 执行应该会自动忽略第一个参数
// 故从1开始取。
*args = argv[i];
args++;
}
char **pa = args;
while(read(0, p, 1) != 0) {
if(*p == ' ' || *p == '\n') {
char cur = *p; // 用于后续判断
*p = '\0'; // 将buf中的当前为置\0
*(pa++) = last_p; // 补充参数
last_p = p + 1;
if(cur == '\n') { // 当前是换行字符时,执行命令
run(argv[1], argsbuf);
pa = args;
}
}
p++;
}
// 若未遇到换行,补充执行
if(pa != args){
*p = '\0';
*(pa++) = last_p;
run(argv[1], argsbuf);
}
while(wait(0) != -1) {};
exit(0);
}
skr