Skip to main content

Section 2.2 Direct Execution

Read the Direct Execution chapter, section 6.1.

Practice 2.2.1.

What are the considerations that the OS needs to keep in mind when setting up time-sharing mechanisms?
  • It must do so with minimal overhead.
  • It must be able to regain control from any processes that want to monopolize the CPU.
  • It must make sure all processes get an equal time.
  • This is not a priority, as long as all processes make progress. But some processes may need more of the CPU’s time.

Practice 2.2.2.

When the system wants to execute a process using direct execution, what are the appropriate steps? Order them (and you may leave some out)

Practice 2.2.3.

Looking at the direct execution model described at the beginning of section 6.1, which OS design goal(s) does it meet?
  • Performance
  • Control
  • Time-sharing
  • This is not an actual "goal" as such.
Read section 6.2 about the problem of restricted operations, and system calls. Make sure you study carefully Figure 6.2, it packs a lot of important information.

Practice 2.2.4.

Determine which of these statements are true.
  • In user mode the program can write to its own memory.
  • To make a system call the user program must use the memory address where the corresponding kernel code exists.
  • We don’t want the user being able to arbitrarily call any kernel address.
  • To make a system call the user program must a special number corresponding to the call they are trying to make.
  • Make sure to re-read the part about system-call numbers.
  • A trap is code that the user writes to try to trick the kernel into letting it run privileged instructions.
  • Read again about the trap and return-from-trap hardware instructions and what they do.
  • The trap table contains a listing of all the system calls that are currently executing.
  • No it only contains references to the address where the actual code for the specific system call resides.
  • In order to start the user program and execute main, the operating system issues a return-from-trap instruction, after some initial setup.
  • Take another closer look at Figure 6.2, especially the beginning of the OS@run section.

Practice 2.2.5.

When the operating system wants to start the user program, it does so by executing a return-from-trap instruction. Why is that, why not a normal function call/jump?
Read section 6.3 about switching between processes and how the system can regain control of the CPU. In particular study Figure 6.3 about the process of a context switch.

Practice 2.2.6.

What is the key idea behind the cooperative approach to process switching?
  • The operating system expects processes to directly call other processes to give them a chance to run.
  • The operating system expects processes to periodically perform system calls, at which point it may choose to switch to another process.
  • The operating system periodically interrupts running processes in order to switch to other processes.
  • When a process is running, there is no direct way for the operating system to interrupt it.

Practice 2.2.7.

What is the key mechanism that allows the OS to regain control of the processor in the non-cooperative approach?
  • A timer interrupt automatically switches to a different process.
  • A timer interrupt regularly executes a kernel-defined interrupt handler, which may initiate a switch to a different process.
  • The user program is expected to call a kernel-defined interrupt handler in order to yield control.
  • No the user program is not in control of this process.

Practice 2.2.8.

When is the timer used in timer interrupts started?
  • It automatically starts whenever the computer turns on.
  • The kernel starts it before it runs each process.
  • The kernel instructs the hardware to start the timer during the kernel’s booting process.

Practice 2.2.9.

In order to perform a context switch from process A to process B, the operating system must perform the following steps (need to place in order, and maybe leave out some steps)
Take a look at the following pieces of code in the xv6-riscv directory:
  • The kernel/proc.h file contains a struct context. Take a look at the order of fields defined there. This is meant to hold the registers of a process when a context switch happens. Note that it only holds 14 registers.
  • Take a look at this page which lists all the registers in the RISC-V architecture. Look specifically at the API-name column. You should find 17 registers (18 if you included the zero register) that are missing from the context structure above. Make sure you identify which registers those are.
  • You’ll find that the t- prefixed and a- prefixed registers are not present in the context switch. If we arrived here as a result of a function call, e.g. a system call, then these t- and a- registers are not guaranteed to be preserved during calls, so the caller would have taken care to store any information they want to preserve from those registers.
  • However if the reason for the context switch was something like a timer interrupt, the user process would not have had the chance to make such a call and preserve those registers. So you might wonder what happens to them. Take a look at the struct trapframe in kernel/proc.h and the uservec: section in kernel/trampoline.S. This is the first code that runs when an interrupt occurs, and you will see that it saves all the registers in this trapframe structure.
  • Also look at userret: in kernel/trampoline.S, which is responsible for restoring the registers whenever we return to a process after an interrupt.
Optional reading: Chapter 4 of the xv6-riscv book outlines the implementation of traps and systems calls in xv6.