Xv6 and Unix utilities
环境准备
ubuntu:
sudo apt-get install git build-essential gdb-multiarch qemu-system-misc gcc-riscv64-linux-gnu binutils-riscv64-linux-gnu
git clone git://g.csail.mit.edu/xv6-labs-2021
cd xv6-labs-2021
git checkout util
make qemu
具体请参考:https://pdos.csail.mit.edu/6.828/2021/tools.html
sleep
Implement the UNIX program sleep for xv6; your sleep should pause for a user-specified number of ticks. A tick is a notion of time defined by the xv6 kernel, namely the time between two interrupts from the timer chip. Your solution should be in the file user/sleep.c.
直接调用系统调用sleep,参数过少或参数过多直接退出
#include "user/user.h"
int main(int argc, char *argv[]) {
if (argc != 2) {
printf("please pass a parameter\n");
exit(0);
}
sleep(atoi(argv[1]));
exit(0);
}
pingpong
Write a program that uses UNIX system calls to ‘‘ping-pong’’ a byte between two processes over a pair of pipes, one for each direction. The parent should send a byte to the child; the child should print “: received ping”, where is its process ID, write the byte on the pipe to the parent, and exit; the parent should read the byte from the child, print “: received pong”, and exit. Your solution should be in the file user/pingpong.c.
调用系统调用pipe创建两个管道,父进程给子进程发送一个字节,然后子进程接受并打印信息,然后子进程给父进程发送一个字节,父进程收到后并打印信息,记得关闭不用的管道。
#include "user/user.h"
int main(int argc, char *argv) {
int pfd1[2], pfd2[2];
pipe(pfd1);
pipe(pfd2);
int pid = fork();
if (pid == 0) {
char ch = '1';
close(pfd1[1]);
close(pfd2[0]);
read(pfd1[0], &ch, 1);
printf("%d: received ping\n", getpid());
write(pfd2[1], &ch, 1);
close(pfd1[0]);
close(pfd2[1]);
} else {
char ch = '1';
close(pfd1[0]);
close(pfd2[1]);
write(pfd1[1], &ch, 1);
read(pfd2[0], &ch, 1);
printf("%d: received pong\n", getpid());
close(pfd1[1]);
close(pfd2[0]);
}
exit(0);
}
Primes
Write a concurrent version of prime sieve using pipes. This idea is due to Doug McIlroy, inventor of Unix pipes. The picture halfway down this page and the surrounding text explain how to do it. Your solution should be in the file user/primes.c.
#include "../kernel/stat.h"
#include "../kernel/types.h"
#include "../user/user.h"
int main() {
int pfd1[15][2], count = 0;
pipe(pfd1[count++]);
int pid = fork();
if (pid == 0) {
int i, num;
close(pfd1[0][1]);
while (1) {
int ret = read(pfd1[0][0], &num, sizeof(num));
if (ret == 0) {
close(pfd1[0][0]); //关闭读端
break;
}
for (i = 2; i <= num / 2; ++i) {
if (num % i == 0) {
break;
}
}
if (i == num / 2 + 1) {
pipe(pfd1[count++]);
pid = fork();
if (pid == 0) {
close(pfd1[0][0]); //关闭读端
close(pfd1[count - 1][1]); //关闭写端
read(pfd1[count - 1][0], &num, sizeof(num));
close(pfd1[count - 1][0]); //关闭读端
printf("prime %d\n", num);
exit(0);
} else {
close(pfd1[count - 1][0]); //关闭读端
write(pfd1[count - 1][1], &num, sizeof(num));
close(pfd1[count - 1][1]); //关闭写端
wait(0);
}
}
}
exit(0);
} else {
int i;
close(pfd1[0][0]);
for (i = 2; i <= 35; i++) {
write(pfd1[0][1], &i, sizeof(i));
}
close(pfd1[0][1]);
wait(0);
exit(0);
}
}
find
Write a simple version of the UNIX find program: find all the files in a directory tree with a specific name. Your solution should be in the file user/find.c.
直接对ls.c进行少量修改即可
#include "kernel/fs.h"
#include "kernel/stat.h"
#include "kernel/types.h"
#include "user/user.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), '\0', DIRSIZ - strlen(p));
return buf;
}
void find(char *path, char *filename) {
char buf[512], *p;
int fd;
struct dirent de;
struct stat st;
if ((fd = open(path, 0)) < 0) {
fprintf(2, "cannot open %s\n", path);
return;
}
if (fstat(fd, &st) < 0) {
fprintf(2, "cannot stat %s\n", path);
close(fd);
return;
}
switch (st.type) {
case T_FILE:
if (strcmp(fmtname(path), filename) == 0) {
printf("%s\n", path);
}
break;
case T_DIR:
if (strlen(path) + 1 + DIRSIZ + 1 > sizeof buf) {
printf("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("cannot stat %s\n", buf);
continue;
}
if (strcmp(buf + strlen(buf) - 2, "/.") == 0 ||
strcmp(buf + strlen(buf) - 3, "/..") == 0)
continue;
find(buf, filename);
}
break;
}
close(fd);
}
int main(int argc, char *argv[]) {
if (argc < 2) {
fprintf(2, "too few parameters");
}
find(argv[1], argv[2]);
exit(0);
}
xargs
Write a simple version of the UNIX xargs program: read lines from the standard input and run a command for each line, supplying the line as arguments to the command. Your solution should be in the file user/xargs.c.
此题主要考察是对命令行参数的提取
xargs可以将从标准输入中的数据转为命令行参数
echo hello too | xargs echo bye等价于echo bye hello too
#include "kernel/param.h"
#include "kernel/stat.h"
#include "kernel/types.h"
#include "user/user.h"
int main(int argc, char *argv[]) {
char *arg[MAXARG];
char buf[1024];
int i = 1, count = 0;
while (argv[i]) {
arg[count++] = argv[i++];
}
char *ptr = buf; //从键盘中读取
char *a = ptr; //指向读取的那个字符串的头部
while (read(0, ptr, 1) == 1) {
if (*ptr == '\n') {
*ptr = '\0';
arg[count++] = a;
arg[count] = 0;
a = ptr + 1;
} else if (*ptr == ' ') {
*ptr = '\0';
arg[count++] = a;
a = ptr + 1;
}
ptr++;
}
int pid = fork();
if (pid == 0) {
exec(arg[0], arg);
} else {
while (wait(0) != -1)
;
}
exit(0);
}