上来直接:
$ cd xv6-riscv-fall19
$ git checkout util
实验指导简要介绍了如何把 xv6 跑起来(make
then make qemu
),如何交作业(make handin
),如何测试成绩(make grade
)。
下面介绍各个子任务如何写。
1. sleep
顾名思义写一个 sleep 例程,休眠一定的 tick 数,tick 的定义是时间中断。
首先 make clean
,然后照猫画虎写一下 user/sleep.c
:
#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
int
main(int argc, char *argv[])
{
if(argc != 2)
write(2, "Error message", strlen("Error message"));
int x = atoi(argv[1]);
sleep(x);
exit(0);
}
按照说明修改 Makefile 运行即可。
2. pingpong
如法炮制。
#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
int
main(int argc, char *argv[])
{
int parent_fd[2], child_fd[2];
pipe(parent_fd); pipe(child_fd);
char buf[64];
if(fork()) {
write(parent_fd[1], "ping", strlen("ping"));
read(child_fd[0], buf, 4);
printf("%d: received %s\n", getpid(), buf);
} else {
read(parent_fd[0], buf, 4);
printf("%d: received %s\n", getpid(), buf);
write(child_fd[1], "pong", strlen("pong"));
}
exit(0);
}
3. primes
照猫画虎。
#include "kernel/types.h"
#include "user/user.h"
void source() {
int i;
for (i = 2; i < 36; i++) {
write(1, &i, sizeof(i));
}
}
void cull(int p) {
int n;
while (read(0, &n, sizeof(n))) {
if (n % p != 0) {
write(1, &n, sizeof(n));
}
}
}
void redirect(int k, int pd[]) {
close(k);
dup(pd[k]);
close(pd[0]);
close(pd[1]);
}
void sink() {
int pd[2];
int p;
if (read(0, &p, sizeof(p))) {
printf("prime %d\n", p);
pipe(pd);
if (fork()) {
redirect(0, pd);
sink();
} else {
redirect(1, pd);
cull(p);
}
}
}
int main(int argc, char *argv[]) {
int pd[2];
pipe(pd);
if (fork()) {
redirect(0, pd);
sink();
} else {
redirect(1, pd);
source();
}
exit();
}
4. find
Bonus 是加 regex 支持,好,抄 user/grep.c
即可。
#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));
memset(buf+strlen(p), ' ', DIRSIZ-strlen(p));
return buf;
}
// Regexp matcher from Kernighan & Pike,
// The Practice of Programming, Chapter 9.
int matchhere(char*, char*);
int matchstar(int, char*, char*);
int
match(char *re, char *text)
{
if(re[0] == '^')
return matchhere(re+1, text);
do{ // must look at empty string
if(matchhere(re, text))
return 1;
}while(*text++ != '\0');
return 0;
}
// matchhere: search for re at beginning of text
int matchhere(char *re, char *text)
{
if(re[0] == '\0')
return 1;
if(re[1] == '*')
return matchstar(re[0], re+2, text);
if(re[0] == '$' && re[1] == '\0')
return *text == '\0';
if(*text!='\0' && (re[0]=='.' || re[0]==*text))
return matchhere(re+1, text+1);
return 0;
}
// matchstar: search for c*re at beginning of text
int matchstar(int c, char *re, char *text)
{
do{ // a * matches zero or more instances
if(matchhere(re, text))
return 1;
}while(*text!='\0' && (*text++==c || c=='.'));
return 0;
}
void
find(char *path, char *re)
{
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(match(re, fmtname(path)))
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(strlen(de.name) == 1 && de.name[0] == '.')
continue;
if(strlen(de.name) == 2 && de.name[0] == '.' && de.name[1] == '.')
continue;
find(buf, re);
}
break;
}
close(fd);
}
int main(int argc, char *argv[]) {
if(argc <= 2)
fprintf(2, "find: not enough params provided");
find(argv[1], argv[2]);
exit();
}
5. xargs
未完成,TODO。
实验总结
无。