Xv6 Scheduling
Learning xv6-riscv-book Chapter 7 Scheduling
- time-share the CPUs: run more processes than CPUs
- transparent to user processes
- multiplexing processes onto CPUs:
- illusion: each process has its own virtual CPU
Multiplexing
Switching CPU among processes:
- sleep/wakeup: process waits for something in the
sleep
syscall - periodically forces a switch: cope with processes that compute for long periods
Illusion: each process has its own CPU.
Challenges:
- How to switch from one process to another?
- How to force switches in a way that transparent to user processes?
- Avoid races when many CPUs switching among processes concurrently.
- each core must remember which process it is executing
- sleep/wakeup: give up CPU, sleep waiting for an event, wake process up: avoid races, loss wakeup notifications
Context switching
- save hte old thread’s CPU registers
- restore previously-saved registers of the new thread
- restore sp (stack pointer) & pc (program counter): switch the executing code.
swtch
(kernel/swtch.S): save and restore for a kernel thread switch: switch to scheduler
void swtch(struct context *old, struct context *new);
- save and restore context (register sets, kernel/proc.h:2)
- swtch does not save
pc
: savera
– holds the return address from whichswtch
was called. - return to instructions pointed by the restored
ra
(the code called swtch)
Yield:
- yield -> sched -> swtch -> return to code called sched:
scheduler
Scheduling
Secheduler: a special thread
- per CPU a scheduler
- running
scheduler()
scheduler
:
-
choose a process to run
-
swtch to run process
-
eventually swtch back to scheduler
-
scheduler acquires
switch_to_proc->lock
, no release
Kernel thread gives up CPU: calls sched
-> switch to scheduler
scheduler & sched: co-rountines (switch between two threads).
p->lock
:
- often acquires in one thread and releases it in other
- once scheduler starts to convert a RUNNABLE process to RUNNING, the lock cannot be released until the kernel thread is completely running (after the swtch, for example in yield).
- interplay between exit and wait, the machinery to avoid lost wakeups
- avoidance of races between a process exiting and other processes reading or writing its state
- …
mycpu and myproc
struct cpu
: Xv6 maintains for each CPU:
- currently running process
- saved registers for the CPU scheduler thread
- count of nested spinlocks needed to manage interrupt disabling
RISC-V giving each CPU a hartid: stored in that CPU’s tp
register while in the kernel:
mstart
setstp
in CPU’s boot (machine mode)usertrapret
savestp
in the trampiline page (user might modify tp)uservec
restores savedtp
when entering the kernel.
mycpu
(kernel/proc.c):
- returns a pointer to the current CPU’s
sturct cpu
- use
tp
to index an array ofstruct cpu
=> find the right one. - interrupts must be disabled to run
mycpu
: if the thread yield and then move to a different CPU, a previously readcpuid
value would no longer be correct.
myproc
(kernel/proc.c):
- disables interrupts
- invokes
mycpu
- fetches current process:
c->proc
- enables