p1.c inside the user directory of xv6-riscv directory with the following content:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
#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);
}
<details class="details details--default" data-variant="default"><summary>Screenshot: creating p1.c inside xv6-riscv/user</summary>
<figure>
<picture>
<!-- Auto scaling with imagemagick -->
<!--
See https://www.debugbear.com/blog/responsive-images#w-descriptors-and-the-sizes-attribute and
https://developer.mozilla.org/en-US/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images for info on defining 'sizes' for responsive images
-->
<source class="responsive-img-srcset" srcset="/assets/img/courses/csc331/process-xv6/01-480.webp 480w,/assets/img/courses/csc331/process-xv6/01-800.webp 800w,/assets/img/courses/csc331/process-xv6/01-1400.webp 1400w," type="image/webp" sizes="95vw" />
<img src="/assets/img/courses/csc331/process-xv6/01.png" width="50%" height="auto" data-zoomable="" loading="lazy" onerror="this.onerror=null; $('.responsive-img-srcset').remove();" />
</picture>
</figure>
</details>
- In `Makefile` under `xv6-riscv`, find the section `UPROGS=` and edit to include the `$U/_p1\` line.
<details class="details details--default" data-variant="default"><summary>Screenshot: Edit xv6-riscv/Makefile</summary>
<figure>
<picture>
<!-- Auto scaling with imagemagick -->
<!--
See https://www.debugbear.com/blog/responsive-images#w-descriptors-and-the-sizes-attribute and
https://developer.mozilla.org/en-US/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images for info on defining 'sizes' for responsive images
-->
<source class="responsive-img-srcset" srcset="/assets/img/courses/csc331/process-xv6/02-480.webp 480w,/assets/img/courses/csc331/process-xv6/02-800.webp 800w,/assets/img/courses/csc331/process-xv6/02-1400.webp 1400w," type="image/webp" sizes="95vw" />
<img src="/assets/img/courses/csc331/process-xv6/02.png" width="50%" height="auto" data-zoomable="" loading="lazy" onerror="this.onerror=null; $('.responsive-img-srcset').remove();" />
</picture>
</figure>
</details>
- Let's rebuild and relaunch xv6. In a terminal, run the followings
~~~bash
cd ~/xv6-riscv
make clean
make
make qemu
ls, you will see the content of the available commands in xv6, which now includes p1.
p2.c inside the user directory of xv6-riscv directory with the following content:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#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);
}
<details class="details details--default" data-variant="default"><summary>Screenshot: creating p2.c inside xv6-riscv/user</summary>
<figure>
<picture>
<!-- Auto scaling with imagemagick -->
<!--
See https://www.debugbear.com/blog/responsive-images#w-descriptors-and-the-sizes-attribute and
https://developer.mozilla.org/en-US/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images for info on defining 'sizes' for responsive images
-->
<source class="responsive-img-srcset" srcset="/assets/img/courses/csc331/process-xv6/05-480.webp 480w,/assets/img/courses/csc331/process-xv6/05-800.webp 800w,/assets/img/courses/csc331/process-xv6/05-1400.webp 1400w," type="image/webp" sizes="95vw" />
<img src="/assets/img/courses/csc331/process-xv6/05.png" width="50%" height="auto" data-zoomable="" loading="lazy" onerror="this.onerror=null; $('.responsive-img-srcset').remove();" />
</picture>
</figure>
</details>
- In `Makefile` under `xv6-riscv`, find the section `UPROGS=` and edit to include the `$U/_p2\` line.
<details class="details details--default" data-variant="default"><summary>Screenshot: Edit xv6-riscv/Makefile</summary>
<figure>
<picture>
<!-- Auto scaling with imagemagick -->
<!--
See https://www.debugbear.com/blog/responsive-images#w-descriptors-and-the-sizes-attribute and
https://developer.mozilla.org/en-US/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images for info on defining 'sizes' for responsive images
-->
<source class="responsive-img-srcset" srcset="/assets/img/courses/csc331/process-xv6/06-480.webp 480w,/assets/img/courses/csc331/process-xv6/06-800.webp 800w,/assets/img/courses/csc331/process-xv6/06-1400.webp 1400w," type="image/webp" sizes="95vw" />
<img src="/assets/img/courses/csc331/process-xv6/06.png" width="50%" height="auto" data-zoomable="" loading="lazy" onerror="this.onerror=null; $('.responsive-img-srcset').remove();" />
</picture>
</figure>
</details>
- Let's rebuild and relaunch xv6. In a terminal, run the followings
~~~bash
cd ~/xv6-riscv
make clean
make
make qemu
ls, you will see the content of the available commands in xv6, which now includes p1 and p2.fork() can be found in kernel/proc.c. fork() system call.
1
2
3
int i, pid;
struct proc *np;
struct proc *p = myproc();
p = myproc() retrieves the current running process (caller of fork()). myproc() is defined in kernel/proc.c.r_tp() (thread pointer register) to find the process on the current CPU.np: placeholder for the new process structure.i: loop index.pid: the child’s PID to return.
1
2
3
4
// Allocate process.
if((np = allocproc()) == 0){
return -1;
}
allocproc() finds an UNUSED struct proc and sets up a kernel stack and page table. kernel/proc.c trapframe, pagetable, and locks the process.-1 on failure, signaling fork error.kernel/param.h).
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;
uvmcopy(...) copies the parent’s entire user address space into the child. uvmcopy() is defined in kernel/vm.c sz is the size of the user memory (stack, heap, etc), defined in struct proc.
1
2
// copy saved user registers.
*(np->trapframe) = *(p->trapframe);
trapframe is a struct defined in kernel/riscv.h
1
2
// Cause fork to return 0 in the child.
np->trapframe->a0 = 0;
a0 is the return value register.a0 will be set to the child’s PID (done after fork returns).a0 is set to 0 here, so that when the child process is ready to resume running, it will see that fork() returned 0.fork() returns in POSIX: 0.
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]);
ofile[] is an array of file pointers in struct proc (📍 in kernel/proc.h)filedup() increases reference counts. kernel/file.c
1
np->cwd = idup(p->cwd);
idup() increments the inode’s ref count.idup() is defined in kernel/fs.c
1
safestrcpy(np->name, p->name, sizeof(p->name));
safestrcpy() is defined in kernel/string.c
1
pid = np->pid;
1
release(&np->lock);
1
2
3
acquire(&wait_lock);
np->parent = p;
release(&wait_lock);
wait_lock so that wait() and exit() (which also touch parent) are synchronized. wait_lock is declared in kernel/proc.c
1
2
3
acquire(&np->lock);
np->state = RUNNABLE;
release(&np->lock);
RUNNABLE, so it can be scheduled. enum procstate in kernel/proc.h
1
return pid;
fork() was called, but will receive return value 0 because of trapframe->a0 = 0.| 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 |