参考大佬
grade-lab-util
文件中的python为python3sudo chown woaixiaoxiao xv6.out
$U/_sleep\
make qemu
,顺便可以自测一下命令是否有效./grade-lab-util sleep
要求
xv6
实现sleep
函数,用户可以指定暂停多少个tickuser/sleep.c
中实现,这个文件要自己创建思路
sleep
函数
user/user.h
头文件就可以使用这个系统调用,但是我没有发现user/user.c
文件,目前我还看不太懂这个系统调用是如何实现的。注意点
代码实现
#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
int main(int argc, char** argv) {
if (argc < 2) {
printf("usage: sleep time_val...\n");
exit(1);
}
int tick = atoi(argv[1]);
sleep(tick);
exit(0);
}
要求
思路
注意点
实现
#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
#define SIZE 1
int main() {
// p1 父写子读
int p1[2];
pipe(p1);
// p2 子写父读
int p2[2];
pipe(p2);
// 子进程
if (fork() == 0) {
// 子进程阻塞p1的写端,p2的读端
close(p1[1]);
close(p2[0]);
char buf[SIZE + 1];
read(p1[0], buf, SIZE);
printf("%d: received ping\n", getpid());
write(p2[1], buf, SIZE);
exit(0);
} else {
// 父进程
close(p1[0]);
close(p2[1]);
char buf[SIZE] = "1";
write(p1[1], buf, SIZE);
read(p2[0], buf, SIZE);
printf("%d: received pong\n", getpid());
}
exit(0);
}
题意
思路
注意点
代码实现
#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
#define INT_SIZE 4
#define RD 0
#define WR 1
#define NULL 0
void recursion(int p[]) {
// 首先关闭写端
close(p[WR]);
// 读取base数字
int base;
int temp = read(p[RD], &base, INT_SIZE);
// 压根没有输入到这个进程
if (temp == 0) {
return;
}
printf("prime %d\n", base);
// 创建管道,并和子进程联动
int p2[2];
pipe(p2);
if (fork() == 0) {
recursion(p2);
exit(0);
}
// 关闭读端
close(p2[RD]);
// 开始不断接受父进程的输入,判断之后传递给子进程
int rec, res;
while (1) {
res = read(p[RD], &rec, INT_SIZE);
// 父进程结束写了
if (res == 0) {
break;
}
// 如果这个数字不是base的倍数,那么写给子进程
if (rec % base != 0) {
write(p2[WR], &rec, INT_SIZE);
}
}
// 写完了,关闭自己的写端
close(p2[WR]);
// 关闭父进程给的管道的读端
close(p[RD]);
wait(NULL);
}
int main() {
int p[2];
pipe(p);
// 子进程
if (fork() == 0) {
recursion(p);
exit(0);
}
// 父进程
close(p[RD]);
for (int i = 2;i <= 35;i++) {
write(p[WR], &i, INT_SIZE);
}
close(p[WR]);
// 等待子进程结束
wait(NULL);
exit(0);
}
题意
find
指令,find dir filename
的作用是找到dir目录中(包括所有子目录中),所有文件名为filename的文件思路
ls.c
文件是如何访问目录的
dirent
这个结构去读取每一个目录项dirent
的name
以及当前目录的path
,可以构造出这个目录项的path
path
和stat
函数,可以把这个目录项的信息给读到stat
结构中stat
结构体的type
可以区分目录和文件
.
和..
,那就递归进去注意点
实现代码
#include "kernel/types.h"
#include "kernel/stat.h"
#include "kernel/fs.h"
#include "user/user.h"
#define O_RDONLY 0
#define MAX_PATH 512
void search(char* dir, char* filename) {
// 获取当前目录的文件描述符
int fd = open(dir, O_RDONLY);
// 不断读取目录项,进行判断
// 这个p是用来拼接这个目录中的子项的路径的
char buf[MAX_PATH];
strcpy(buf, dir);
char* p = buf + strlen(buf);
*p = '/';
p++;
// 正式读取每一行,并根据目录还是文件进行讨论
struct dirent de;
struct stat st;
while (read(fd, &de, sizeof(de)) == sizeof(de)) {
// 无效
if (de.inum == 0) {
continue;
}
// 拼接出目录的这一项的path
memmove(p, de.name, DIRSIZ);
p[DIRSIZ] = 0;
// 取出这一项的信息
stat(buf, &st);
// 如果是文件
if (st.type == T_FILE) {
// 文件名相同,打印path
if (strcmp(de.name, filename) == 0) {
printf("%s\n", buf);
}
} else if (st.type == T_DIR) {
// 这一项是目录,只要不是 . 或者 .. 那就递归进去
if (strcmp(de.name, ".") != 0 && strcmp(de.name, "..") != 0) {
search(buf, filename);
}
}
}
// 记得关闭文件描述符
close(fd);
}
int main(int argc, char** argv) {
if (argc != 3) {
printf("usage: find dir filename\n");
exit(1);
}
char* dir = argv[1];
char* filename = argv[2];
search(dir, filename);
exit(0);
}
题意
xargs a b
代表执行a
程序,a
程序的第一个参数是b
,xargs
会从标准输
入中按行读取
,将每一行作为a
的其他参数,假如读入了某一行是c d
,那么说明a
程序有三个参数,依次是b c d
xargs
按行读取的意思是,对于每一行,它都会读取这一行所有被空格分开的值,将它作为a程序的参数
。假如有n
行,就会执行n
次a程序
echo hello too | xargs echo bye
|
的作用是把它前面的运行结果给放到后面这个函数的标准输入中hello too
作为一行放到了xargs
函数的标准输入里,也就是说,如果xargs
能够调用scanf
函数,就可以读到hello too
思路
\n
为结束符,实验文档推荐我们每一次读一个字节,这样比较好判断\n
,可以通过read函数实现读取注意点
while (wait(0) != -1)
实现代码
#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
#include "kernel/param.h"
#define stdin 0
#define NULL 0
#define MAX_SIZE 1024
#define CHAR_SIZE 1
char* strdup(char* p) {
char* temp = (char*)malloc(strlen(p) + 1);
memcpy(temp, p, strlen(p));
return temp;
}
int main(int argc, char* argv[]) {
// 初始化我们要传递给execute函数的参数
char* args[MAXARG + 2];
for (int i = 1;i < argc;i++) {
args[i - 1] = argv[i];
}
int arg_count = argc - 1;
// 从标准输入一行一行地读
char input_line[MAX_SIZE];
while (1) {
// 最外层的这个while循环,每循环一次代表要execute一次
// 因此arg_count和p都应该重置,其中p用来操作input_line
arg_count = argc - 1;
char* p = input_line;
// 用read从标准输入端读
int res;
while ((res = read(stdin, p, CHAR_SIZE)) > 0) {
// 如果读入的既不是空格也不是换行,那就让p++,继续读入这个参数
if (*p != ' ' && *p != '\n') {
p++;
// 读入的是空格,说明第一个参数已经完成了
// 那么我们可以将这个参数写入args,并且修改p指针
} else if (*p == ' ') {
*p = '\0';
args[arg_count] = strdup(input_line);
arg_count++;
p = input_line;
// 读入的是换行,说明已经完全读完了
// 存当前的这个参数到args,并且为args增加一个结尾标志null
// 然后fork,exec
} else if (*p == '\n') {
*p = '\0';
args[arg_count] = strdup(input_line);
arg_count++;
args[arg_count] = NULL;
// 子进程,去exec
if (fork() == 0) {
exec(args[0], args);
exit(0);
}
// 父进程,现在应该去读新的一行了,break
break;
}
}
// 读完了
if (res <= 0) {
break;
}
}
// 等待所有子进程结束
while (wait(0) != -1) {
}
exit(0);
}