This experiment mainly learned some commonly used system calls.
Lab 1: Unix utilities
Boot xv6 (easy)
git clone, switch branches, qemu. Just proceed as required.
$ git clone git://g.csail.mit.edu/xv6-labs-2020 $ cd xv6-labs-2020 $ git checkout util $ makeqemu
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); } }
Add sleep to the build target in the Makefile.
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)
For pipe problems, use fork() to copy this process to create a child process, and then use pipes to communicate with each other.
#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], & amp;buff,1); printf("%d: received pong\ ",n); }else{ char buff; read(pp2c[0], & amp;buff,1); printf("%d: received ping\ ",n); write(pp2p[1], & amp;buff,1); } exit(0); }
primes (moderate) / (hard)
Observe the picture below to understand, and use fork to implement the function of prime number sieve.
// primes.c #include "kernel/types.h" #include "kernel/stat.h" #include "user/user.h" void sieve(int pleft[2]){<!-- --> int p ; read(pleft[0] , & amp;p,sizeof(p)); if(p == -1){<!-- --> exit(0); } printf("prime %d\ ", p); int pright[2]; pipe(pright); if(fork() == 0){<!-- --> // child process close(pright[1]); close(pleft[0]); sieve(pright); }else{<!-- --> close(pright[0]); int buff; while(read(pleft[0] , & amp;buff,sizeof(buff)) & amp; & amp; buff != -1){<!-- --> if(buff %p != 0 ){<!-- --> write(pright[1] , & amp;buff,sizeof(buff)); } } buff = -1; write(pright[1] , & amp;buff,sizeof(buff)); wait(0); exit(0); } } int main(int argc,char* argv[]){<!-- --> int inputpipe[2]; pipe(inputpipe); if(fork() == 0){<!-- --> // child process close(inputpipe[1]); sieve(inputpipe); exit(0); }else{<!-- --> close(inputpipe[0]); int i; for( i = 2 ; i <=35;i + + ){<!-- --> write(inputpipe[1] , & amp;i,sizeof(i) ); } i =-1; write(inputpipe[1] , & amp;i,sizeof(i) ); } wait(0); exit(0); }
find (moderate)
Based on the transformation of 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\ ", path); return; } if(fstat(fd, & amp;st) < 0){<!-- --> fprintf(2, "ls: cannot stat %s\ ", path); close(fd); return; } switch(st.type){<!-- --> case T_FILE: if(strcmp(path + strlen(path) - strlen(target) ,target) == 0) printf("%s\ ", path); break; case T_DIR: if(strlen(path) + 1 + DIRSIZ + 1 > sizeof buf){<!-- --> printf("find: path too long\ "); break; } strcpy(buf, path); p = buf + strlen(buf); *p + + = '/'; while(read(fd, & amp;de, sizeof(de)) == sizeof(de)){<!-- --> if(de.inum == 0|| strcmp(de.name, ".")==0 || strcmp(de.name, ".." )==0 ) continue; memmove(p, de.name, DIRSIZ);//It will be overwritten every time it loops p[DIRSIZ] = 0; if(stat(buf, & amp;st) < 0){<!-- --> printf("find: cannot stat %s\ ", buf); continue; } // printf(buf); // printf("\ "); find(buf, target); // Recursive search \t\t } break; } close(fd); } int main(int argc, char *argv[]) {<!-- --> if(argc < 3){<!-- --> exit(0); } char target[512]; target[0] = '/'; // Add / at the beginning of the file name to be searched for strcpy(target + 1, argv[2]); find(argv[1], target); exit(0); }
xargs (moderate)
Introduction to xargs
Overall idea:
- Save the parameters passed in by the xargs command to an array of pointers, with each pointer pointing to a parameter;
- Parse the input parameters. If ‘ ‘ or \
is encountered, save the parameters to the pointer array. Use exec to run each time a line is read. - The last line is judged and run separately, in case the last line does not have a newline character
// 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]; // Memory pool used when reading char *p = buf, *last_p = buf; // End and start pointers of the current parameter char *argsbuf[128]; //All parameter list, string pointer array, including parameters passed in by argv and parameters read in by stdin char **args = argsbuf; // Point to the first parameter in argsbuf read from stdin for(int i=1;i<argc;i + + ) {<!-- --> //Add the parameters provided by argv to the final parameter list *args = argv[i]; args + + ; } char **pa = args; while(read(0,p,1) != 0 ){<!-- --> if(*p == ' ' || *p == '\ '){<!-- --> *p = '\0'; *(pa + + ) = last_p; last_p = p + 1; if(*p == '\ '){<!-- --> *pa = 0; run(argv[1],argsbuf); pa = args; } } p + + ; } if(pa != args) {<!-- --> // If the last line is not a blank line //Finish the last parameter *p = '\0'; *(pa + + ) = last_p; // End the last line *pa = 0; // Use null at the end of the parameter list to identify the end of the list //Execute the last line of instructions run(argv[1], argsbuf); } while(wait(0) != -1) {<!-- -->}; exit(0); }