MIT 6.828 Util Lab
在xv6操作系统上实现一些实用小程序
实验准备(Lab1 Boot xv6)
在ubuntu18上进行实验
根据2021年的实验网站进行配置,但是发现用不了qemu-system-riscv64,只能自己手动构建riscv的toolchain,参考2020年的网站。
项目克隆下来后,使用make时提示riscv64-linux-gnu-gcc的命令行参数错误,参照这个issue更改Makefile。
最终可以make qemu了。
Lab2 sleep
利用xv6的系统调用,实现sleep命令。
使用 $ ./grade-lab-util sleep
对实验打分
#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
int main(int argc, char* argv[]) {
if (argc != 2) {
fprintf(2, "Usage: sleep [seconds]\n");
exit(1);
}
int seconds = atoi(argv[1]);
sleep(seconds);
exit(0);
}
Lab3 pingpong
通过创建管道实现父子进程通信,注意,对于一个进程来说,管道是单向的,所以要实现双向通讯,必须创建两个管道。
read(read_pipe, buf, buf_len)是阻塞的,除非关闭了管道的所有写端口(包括子进程),read返回0。
#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
int main(void) {
int p2c[2], c2p[2];
char buf[1];
if(pipe(p2c) < 0) {
fprintf(2, "%s\n", "Cannot create pipe p2c.");
exit(1);
}
if(pipe(c2p) < 0) {
fprintf(2, "%s\n", "Cannot create pipe c2p.");
exit(1);
}
if (fork() == 0) {
// child process
close(p2c[1]); // close the write to parent
read(p2c[0], buf, 1);
printf("%d: received ping\n", getpid()); // 2. child receive the byte
close(c2p[0]);
write(c2p[1], buf, 1); // 3. tell parent
close(p2c[0]);
close(c2p[1]);
exit(0);
} else {
close(p2c[0]); // close the read
write(p2c[1], "a", 1); // 1. send a byte to child
close(c2p[1]);
read(c2p[0], buf, 1);
printf("%d: received pong\n", getpid()); // 4. parent got the byte
close(p2c[1]);
close(c2p[0]);
exit(0);
}
}
Lab4 primes
使用管道实现素数筛,每一个阶段实现打印管道中到来的第一个素数a,判断剩余到达的数是否能被a整除,如果不能,则送入下一阶段的管道。参考实现。
#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
const int limit = 35;
void panic(char* buf) {
fprintf(2, "%s\n", buf);
exit(1);
}
void cull(int readPipe, int writePipe, int prime) {
uint32 n;
while (read(readPipe, &n, 4)) {
if (n % prime != 0) {
write(writePipe, &n, 4);
}
}
}
/**
* return the another pipe contains group of numbers that cannot be divided by prime
* @param prime
* @param readPipe
* @return
*/
void primeFilters(int readPipe) {
uint32 prime;
if (read(readPipe, &prime, 4)) {
printf("prime %d\n", prime);
int newPipe[2];
if (pipe(newPipe) < 0) {
panic("cannot create pipe.");
}
if (fork() == 0) {
// child generate new sequence
close(newPipe[0]);
cull(readPipe, newPipe[1], prime);
close(newPipe[1]);
} else {
// parent forward the pipe to next stage
close(newPipe[1]);
primeFilters(newPipe[0]);
close(newPipe[0]);
}
}
}
int main(void) {
int p[2];
if (pipe(p) < 0) {
panic("Cannot create pipe.");
}
if (fork() == 0) {
// child
close(p[1]);
primeFilters(p[0]);
close(p[0]);
} else {
// parent
close(p[0]);
for (uint32 i = 2; i <= limit; ++i) {
write(p[1], &i, 4);
}
close(p[1]);
wait(0); // wait all children
}
exit(0);
}
Lab5 find
递归得查找目录,用了来自ls.c的fmtname来规范化文件名,同时借鉴grep.c的正则匹配。
#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
#include "kernel/fs.h"
char curDir[DIRSIZ], parDir[DIRSIZ];
int match(char*, char*);
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;
}
char *trim(char *path) {
char *p;
static char buf[DIRSIZ];
for (p = path + strlen(path) - 1; p >= path && *p == ' '; p--)
;
p++;
memmove(buf, path, p-path);
buf[p-path] = 0;
return buf;
}
void find(char* path, char* name) {
int fd;
struct dirent de;
char buf[512], *p;
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;
}
char *dirname = fmtname(path);
// if (strcmp(name, dirname) == 0) { // compare
if (match(name, trim(dirname))) {
printf("%s\n", dirname);
return;
}
if (st.type == T_DIR) {
if(strlen(path) + 1 + DIRSIZ + 1 > sizeof buf){
printf("find: path too long\n");
return;
}
strcpy(buf, path);
p = buf+strlen(buf);
*p++ = '/';
while(read(fd, &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;
}
char *itemname = fmtname(buf);
// if (!strcmp(name, itemname)) { // compare
if (match(name, trim(itemname))) {
printf("%s\n", buf);
} else {
if (st.type == T_DIR) {
if (strcmp(curDir, itemname) && strcmp(parDir, itemname)){
find(buf, name);
}
}
}
}
}
}
int main(int argc, char* argv[]) {
if (argc < 3) {
fprintf(2, "Usage: find\n");
exit(1);
}
while (argv[1][strlen(argv[1])-1] == '/') {
argv[1][strlen(argv[1])-1] = 0;
}
strcpy(curDir, fmtname("."));
strcpy(parDir, fmtname(".."));
for (int i = 2; i < argc; i++) {
// char nameBuf[DIRSIZ];
// strcpy(nameBuf, fmtname(argv[i]));
find(argv[1], argv[i]);
}
exit(0);
}
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;
}
Lab6 xargs
没有按照实验的要求一次读取一个字符直至'\n',而是批量读取,之后来分割,所以代码有些复杂。在运用指针数组的时候注意。
#include "kernel/types.h"
#include "kernel/stat.h"
#include "kernel/param.h"
#include "user/user.h"
int main(int argc, char* argv[]) {
if (argc < 2) {
fprintf(2, "Usage: %s cmd args...\n", argv[0]);
exit(1);
}
char *execargv[MAXARG];
for (int i = 1; i < argc; ++i) {
execargv[i-1] = argv[i];
}
char buf[1024];
int n, m;
m = 0;
while ((n = read(0, buf+m, sizeof(buf)-m-1)) > 0) {
char *bp = buf + m, *p;
p = bp;
while (p < buf + m + n) {
if (*p == '\n') {
*p = '\0';
}
p++;
}
m += n;
buf[m] = '\0';
p = bp;
while (p < bp + n) {
if (strlen(p) == 0) {
p++;
continue;
}
if (fork() == 0) {
// child
// strcpy(execargv[argc], p); // WRONG!! copy the args from stdin
execargv[argc-1] = p; // 注意未分配内存,只保存栈指针
execargv[argc] = 0;
exec(execargv[0], execargv);
fprintf(2, "exec %s failed\n", execargv[0]);
exit(1);
} else {
wait(0);
}
p += (strlen(p) + 1);
}
}
exit(0);
}
END