这个实验主要学习了常用的一些系统调用。
Lab 1: Unix utilities
Boot xv6 (easy)
git克隆,切换分支,qemu。根据要求进行操作即可。
$ git clone git://g.csail.mit.edu/xv6-labs-2020
$ cd xv6-labs-2020
$ git checkout util
$ make qemu
sleep (easy)
#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
int main(int argc ,char *argv[])
{
if(argc < 2 )
{
fprintf(2,"please enter a number!");
exit(1);
}else{
int n = atoi(argv[1]);
sleep(n);
exit(0);
}
}
在 Makefile 中将 sleep 加入构建目标里。
UPROGS=\
$U/_cat\
$U/_echo\
$U/_forktest\
$U/_grep\
$U/_init\
$U/_kill\
$U/_ln\
$U/_ls\
$U/_mkdir\
$U/_rm\
$U/_sh\
$U/_stressfs\
$U/_usertests\
$U/_grind\
$U/_wc\
$U/_zombie\
$U/_sleep\ . # here !!!
pingpong (easy)
管道题,使用 fork() 复制本进程创建子进程,然后使用管道进行相互通信。
#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
int main(int argc ,char *argv[])
{
int pp2c[2],pp2p[2];
pipe(pp2c);
pipe(pp2p);
int n = fork();
if(n != 0 ){
write(pp2c[1],"a",1);
char buff;
read(pp2p[0],&buff,1);
printf("%d: received pong\n",n);
}else{
char buff;
read(pp2c[0],&buff,1);
printf("%d: received ping\n",n);
write(pp2p[1],&buff,1);
}
exit(0);
}
primes (moderate) / (hard)
观察下图进行进行理解,使用fork实现素数筛的功能。
// primes.c
#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
void sieve(int pleft[2]){
int p ;
read(pleft[0] ,&p,sizeof(p));
if(p == -1){
exit(0);
}
printf("prime %d\n", p);
int pright[2];
pipe(pright);
if(fork() == 0){
// 子进程
close(pright[1]);
close(pleft[0]);
sieve(pright);
}else{
close(pright[0]);
int buff ;
while(read(pleft[0] ,&buff,sizeof(buff)) && buff != -1){
if(buff %p != 0 ){
write(pright[1] ,&buff,sizeof(buff));
}
}
buff = -1;
write(pright[1] ,&buff,sizeof(buff));
wait(0);
exit(0);
}
}
int main(int argc,char* argv[]){
int inputpipe[2];
pipe(inputpipe);
if(fork() == 0){
// 子进程
close(inputpipe[1]);
sieve(inputpipe);
exit(0);
}else{
close(inputpipe[0]);
int i ;
for( i = 2 ; i <=35;i++){
write(inputpipe[1] ,&i,sizeof(i) );
}
i =-1;
write(inputpipe[1] ,&i,sizeof(i) );
}
wait(0);
exit(0);
}
find (moderate)
根据ls.c 改造得到
#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
#include "kernel/fs.h"
void find(char *path,char *target)
{
char buf[512], *p;
int fd;
struct dirent de;
struct stat st;
if((fd = open(path, 0)) < 0){
fprintf(2, "ls: cannot open %s\n", path);
return;
}
if(fstat(fd, &st) < 0){
fprintf(2, "ls: cannot stat %s\n", path);
close(fd);
return;
}
switch(st.type){
case T_FILE:
if(strcmp(path+strlen(path) - strlen(target) ,target) == 0)
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|| strcmp(de.name, ".")==0 || strcmp(de.name, ".." )==0 )
continue;
memmove(p, de.name, DIRSIZ);//每次循环都会被覆盖
p[DIRSIZ] = 0;
if(stat(buf, &st) < 0){
printf("find: cannot stat %s\n", buf);
continue;
}
// printf(buf);
// printf("\n");
find(buf, target); // 递归查找
}
break;
}
close(fd);
}
int main(int argc, char *argv[])
{
if(argc < 3){
exit(0);
}
char target[512];
target[0] = '/'; // 为查找的文件名添加 / 在开头
strcpy(target+1, argv[2]);
find(argv[1], target);
exit(0);
}
xargs (moderate)
整体思路:
- 将xargs命令传入的参数保存至指针数组,每个指针指向一个参数;
- 解析输入参数,如果遇到’ ’ 或者\n 就将参数保存至指针数组,每次读取完成一行就使用exec进行运行
- 最后一行进行单独判断运行,万一最后一行没有换行符
// xargs.c
#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
#include "kernel/fs.h"
void run(char *program , char ** args)
{
if(fork() == 0 ){
exec(program,args);
exit(0);
}
return ;
}
int main(int argc,char* argv[]){
char buf[2048]; // 读入时使用的内存池
char *p = buf, *last_p = buf; // 当前参数的结束、开始指针
char *argsbuf[128]; // 全部参数列表,字符串指针数组,包含 argv 传进来的参数和 stdin 读入的参数
char **args = argsbuf; // 指向 argsbuf 中第一个从 stdin 读入的参数
for(int i=1;i<argc;i++) {
// 将 argv 提供的参数加入到最终的参数列表中
*args = argv[i];
args++;
}
char **pa = args;
while(read(0,p,1) != 0 ){
if(*p == ' ' || *p == '\n'){
*p = '\0';
*(pa++) = last_p;
last_p = p+1;
if(*p == '\n'){
*pa = 0;
run(argv[1],argsbuf);
pa = args;
}
}
p++;
}
if(pa != args) { // 如果最后一行不是空行
// 收尾最后一个参数
*p = '\0';
*(pa++) = last_p;
// 收尾最后一行
*pa = 0; // 参数列表末尾用 null 标识列表结束
// 执行最后一行指令
run(argv[1], argsbuf);
}
while(wait(0) != -1) {};
exit(0);
}