Boot xv6 (easy)
根据官网指引,在 make qemu 步骤发生问题(runcmd函数内检测到无限递归):
user/sh.c: In function 'runcmd':
user/sh.c:58:1: error: infinite recursion detected [-Werror=infinite-recursion]
58 | runcmd(struct cmd *cmd)
| ^~~~~~
看到csdn上也有类似的提问,https://ask.csdn.net/questions/7829950
根据这个帖子里的回答,在 runcmd 函数前添加 __attribute__((noreturn)) 即 Make qemu 成功。
steps:
在xv6-labs-2020路径下执行 make qemu
Grade
在xv6-labs-2020路径下执行 make grade 可以评分。
sleep (easy)
参考 user/echo.c 实现 sleep.c;
#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
int main(int argc,char *argv[])
{
if(2!=argc){
fprintf(2, "usage: sleep seconds\n");
exit(1);
}
sleep(atoi(argv[1]));
exit(0);
}
修改 makefile
UPROGS=\
$U/_sleep\
...
ifeq ($(LAB),sleep)
UPROGS += \
$U/_sleep
endif
在 xv6-labs-2020路径下执行
./grade-lab-util sleep
查看是否通过。
pingpong (easy)
参考 riscv第一章内容实现,注意:
1. 子进程先read再write;
2. 父子进程完成工作后close管道的读写端
3. 为了避免打印乱序,父进程中在打印之前调用 wait 系统调用,等待子进程完成工作。
#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
int main(int argc,char* argv[])
{
int pipes[2];
pipe(pipes);
char buf[2];
int pid=0;
if(0==fork()){
//child
memset(buf,0,2);
read(pipes[0],buf,1);
pid=getpid();
printf("%d: received ping\n",pid);
write(pipes[1],"a",2);
close(pipes[0]);
close(pipes[1]);
exit(0);
}
else{
memset(buf,0,2);
write(pipes[1],"a",2);
read(pipes[0],buf,1);
pid=getpid();
wait((int*)0);
printf("%d: received pong\n",pid);
close(pipes[0]);
close(pipes[1]);
exit(0);
}
exit(0);
}
find (moderate)
char *fmtname ( char *path); 返回 path 路径字符串中最右斜杆 / 后子串,如 /hello/world 返回 world
#include <iostream>
#include <stdlib.h>
#include <string.h>
int main()
{
char buf[100] = "hello world";
if (*(buf + strlen(buf)) == '\0') {
printf("buf + strlen(buf) points to a \\0\n");
}
char* p = buf + 2;
printf("strlen(p): <%d>\n", strlen(p));
printf("p: <%s>\n", p);
return 0;
}
/*
buf + strlen(buf) points to a \0
strlen(p): <9>
p: <llo world>
注意,若 make qemu 报错:error: unknown type name 'uint'
修改头文件的include顺序,最简单就直接从 ls.c 里复制一下就行,不要随便修改 #include 的顺序
注意点:
1. fstat 得到的文件类型应考虑 T_FILE 与 T_DIR以外的类型
2. 获取路径中最右斜杆后的文件名,可以用个全局的字符数组
3. 注意及时close被open的描述符
#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
#include "kernel/fs.h"
#include "stdbool.h"
char buf[DIRSIZ + 1] = {0};
char *fmtname(char *path)
{
memset(buf, 0, sizeof(buf));
char *p;
for (p = path + strlen(path); p >= path && *p != '/'; p--)
;
p++;
if (strlen(p) >= DIRSIZ)
return p;
memcpy(buf, p, strlen(p));
return buf;
}
void find(char *path, char *file)
{
if (strlen(path) <= 0)
return;
char buf[512] = {0};
strcpy(buf, path);
struct stat st;
struct dirent de;
int fd = 0;
if ((fd = open(buf, 0)) < 0)
{
return;
}
if (fstat(fd, &st) < 0)
{
close(fd);
return;
}
if (st.type == T_FILE)
{
char *filename = fmtname(buf);
if (strcmp(filename, file) == 0)
{
printf("%s\n", buf);
}
close(fd);
return;
}
else if (st.type == T_DIR)
{
if (strlen(path) + 1 + DIRSIZ + 1 > sizeof buf)
{
close(fd);
return;
}
char *p = buf + strlen(buf);
*p++ = '/';
while (read(fd, &de, sizeof(de)) == sizeof(de))
{
if (strcmp(de.name, ".") == 0 || strcmp(de.name, "..") == 0)
continue;
if (de.inum == 0)
continue;
memmove(p, de.name, DIRSIZ);
p[DIRSIZ] = 0;
find(buf, file);
}
}
else
{
close(fd);
return;
}
}
int main(int argc, char *argv[])
{
if (argc < 3)
{
fprintf(2, "usage: find . filename");
exit(1);
}
char dir[512] = {0};
char file[512] = {0};
memcpy(dir, argv[1], strlen(argv[1]));
memcpy(file, argv[2], strlen(argv[2]));
find(dir, file);
printf("bye\n");
return 0;
}
xargs
简化版的 UNIX xargs程序:从标准输入读取多行,对每一行执行命令。,该行作为命令的参数。
比如
echo hello too | xargs echo bye
这里,echo bye 为命令,hello too 为参数。