Process in xv6

Editing files in xv6

Since the csc331 container mounts the workspace directory on the host machine into /workspace, you are able to edit contents directly from the host machine via an IDE. The screenshot belows show a VSCode IDE session into the xv6-riscv repo that had been cloned into the host machine’s workspace folder and editing a file called xv6-test.txt.

WarningDo not open git repository of parent folder

You can also leverage the Terminal space of VSCode to docker exec into the container and test your code modifications.

This file also shows up inside the csc331 container.

Screenshot: Contents of /workspace inside container

Going forward, you can edit all files in the workspace directory from your host computer and they will be reflected immediately inside the container. This will help with all hands-on activities, labs, and assignments for the class.

How does fork() behave in xv6?

1
2
3
4
5
6
7
8
9
10
11
12
13
#include "kernel/types.h"
#include "user/user.h"

int main() {
  int pid = fork();
  if (pid == 0) {
    printf("Child: my pid is %d\n", getpid());
    exit(0);
  } else {
    printf("Parent: my pid is %d, child is %d\n", getpid(), pid);
  }
  exit(0);
}
Screenshot: creating p1.c inside xv6-riscv/user
Screenshot: Edit xv6-riscv/Makefile
1
2
3
4
cd ~/xv6-riscv
make clean
make
make qemu
Screenshot: content of ls
What do you expect to see, and what do you have? Why?

What about wait()?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include "kernel/types.h"
#include "user/user.h"

int main() {
  int pid = fork();
  if (pid == 0) {
    printf("Child: my pid is %d\n", getpid());
    exit(0);
  } else {
    wait(0);
    printf("Parent: my pid is %d, child is %d\n", getpid(), pid);
  }
  exit(0);
}
Screenshot: creating p2.c inside xv6-riscv/user
Screenshot: Edit xv6-riscv/Makefile
1
2
3
4
cd ~/xv6-riscv
make clean
make
make qemu

The implementation of fork() in xv6

InfoDetails
1
2
3
int i, pid;
struct proc *np;
struct proc *p = myproc();
InfoDetails
1
2
3
4
// Allocate process.
if((np = allocproc()) == 0){
    return -1;
}
InfoDetails
1
2
3
4
5
6
7
// Copy user memory from parent to child.
if(uvmcopy(p->pagetable, np->pagetable, p->sz) < 0){
    freeproc(np);
    release(&np->lock);
    return -1;
}
np->sz = p->sz;
InfoDetails
1
2
// copy saved user registers.
*(np->trapframe) = *(p->trapframe);
InfoDetails
1
2
// Cause fork to return 0 in the child.
np->trapframe->a0 = 0;
InfoDetails
1
2
3
4
// increment reference counts on open file descriptors.
for(i = 0; i < NOFILE; i++)
    if(p->ofile[i])
    np->ofile[i] = filedup(p->ofile[i]);
InfoDetails
1
np->cwd = idup(p->cwd);
InfoDetails
1
safestrcpy(np->name, p->name, sizeof(p->name));
InfoDetails
1
pid = np->pid;
InfoDetails
1
release(&np->lock);
InfoDetails
1
2
3
acquire(&wait_lock);
np->parent = p;
release(&wait_lock);
InfoDetails
1
2
3
acquire(&np->lock);
np->state = RUNNABLE;
release(&np->lock);
InfoDetails
1
return pid;
Summary of key structures and calls
Symbol Description File
struct proc Per-process control block kernel/proc.h
myproc() Get current process kernel/proc.c
allocproc() Allocate and initialize new proc kernel/proc.c
uvmcopy() Copy address space (page tables) kernel/vm.c
trapframe Saved user-space CPU registers kernel/riscv.h
filedup() Increment file descriptor refcount kernel/file.c
idup() Increment inode refcount kernel/fs.c
safestrcpy() Safe string copy kernel/string.c
wait_lock Lock for parent/child relationships kernel/proc.c