We will be using qemu to emulate our xv6 kernel. Luckily, the Makefile has already setup everything for us. Once we clone the repo and follow the instructions to find correct branch. Then we are good to go.
sleep (easy)
Just a simple sleep program to hang the process for a user-specified number of ticks through command line argument. Use sleep system call will be able to handle this.
Don’t forget to add new user program in the Makefile‘s UPROGS variable
pingpong (easy)
This section is to get us familiar with fork and pipe syscall and use pipe to communicate with different processes. We could refer the man page of Linux syscall (or just read the kernel source code).
if (read(pipefd[0], buf, 1) != 1) { fprintf(2, "fail to read in child!\n"); exit(1); } close(pipefd[0]);
printf("%d: received ping\n", pid);
if (write(pipefd[1], buf, 1) != 1) { fprintf(2, "fail to write in child!\n"); exit(1); } close(pipefd[1]);
exit(0); } else { /* Parent */ pid = getpid();
if (write(pipefd[1], msg, 1) != 1) { fprintf(2, "fail to write in parent!\n"); exit(1); } close(pipefd[1]);
/* Wait for child to terminate */ wait(0);
if (read(pipefd[0], buf, 1) != 1) { fprintf(2, "fail to read in parent!\n"); exit(1); } close(pipefd[0]);
printf("%d: received pong\n", pid);
exit(0); } }
Don’t forget to check all the return code of all your syscalls!
primes (moderate)/(hard)
The hardest part in this lab. We need to write a concurrent program (by forking child process) to sieve the prime numbers. The core part is to understand the graph below:
Each process should sieve out the multiple of the prime number it is priting. It is easy to make us think aobut recurrance relation to fork and sieve processes because each process basically follow the same logic.
voidprimes(int *pipefd1) { int prime, num, pid; int pipefd2[2]; /* Another pipe for child */
/* Child don't need to write */ close(pipefd1[1]);
if (read(pipefd1[0], &prime, sizeof(int)) != sizeof(int)) { fprintf(2, "fail to read!\n"); exit(1); }
printf("prime %d\n", prime);
/* Make sure what we read is not the last one */ if (read(pipefd1[0], &num, sizeof(int)) > 0) { if (pipe(pipefd2) < 0) { fprintf(2, "pipe error!\n"); exit(1); }
for (int i = START; i <= END; i++) { if (write(pipefd[1], &i, sizeof(int)) != sizeof(int)) { fprintf(2, "fail to write!\n"); exit(1); } }
close(pipefd[1]); wait(0); }
exit(0); }
find (moderate)
This part require us to understand how to manipulate files through syscalls, fstat, read. We could reference user/ls.c. Once we reach a directory, recursively call find function to find that directory.
We want to make a simpler version of UNIX xargs program by providing the initial arguments for the program and use stdin to read additional arguments and append new arguments to the initial arguments and forkexec the program.