Lecture 2 - Processes: Virtualizing the CPU
Instructor: Michael Swift & Tej Chajed Topics: Processes, process state, CPU virtualization, limited direct execution, context switching
Learning Outcomes
- Describe the process abstraction
- Argue why limited direct execution is a good approach for CPU virtualization
- Reproduce the mechanism for limited direct execution
What is a Process?
Process: An execution stream in the context of a process state.
Execution stream: A stream of executing instructions; a running piece of code; a “thread of control.”
Process state: Everything that the running code can affect or be affected by.
Process state includes:
- Registers — general purpose, floating point, status, program counter, stack pointer
- Address space — heap, stack, and code
- Open files
A process is different from a program:
- Program: Static code and static data (lives on disk)
- Process: Dynamic instance of code and data (lives in memory)
Can have multiple process instances of the same program (e.g., many users running ls at the same time).
Process Creation
Process Creation:
- Program sits on disk (code + static data)
- OS loads code and static data into memory
- OS allocates heap and stack in the address space
- Process is ready to execute
Two Ways to Create a Process
- Build a new empty process from scratch
- Copy an existing process and change it appropriately
Option 1: New Process from Scratch
- Steps:
- Load specified code and data into memory; create empty call stack
- Create and initialize PCB (make look like context-switch)
- Put process on ready list
- Advantages: No wasted work
- Disadvantages: Difficult to setup process correctly and to express all possible options
- Process permissions, where to write I/O, environment variables
- Example: Windows has call with 10 arguments
Option 2: Clone Existing Process and Change
- Example: Unix
fork()andexec()fork(): Clones calling processexec(char *file): Overlays file image on calling process
fork():- Stop current process and save its state
- Make copy of code, data, stack, and PCB
- Add new PCB to ready list
exec(char *file):- Replace current data and code segments with those in specified file
- Advantages: Flexible, clean, simple
- Disadvantages: Wasteful to perform copy and then overwrite memory
Unix Shell Implementation
while (1) {
char *cmd = getcmd();
int retval = fork();
if (retval == 0) {
// This is the child process
// Setup the child's process environment here
// E.g., where is standard I/O, how to handle signals?
exec(cmd);
// exec does not return if it succeeds
printf("ERROR: Could not execute %s\n", cmd);
exit(1);
} else {
// This is the parent process; Wait for child to finish
int pid = retval;
wait(pid);
}
}
Virtualizing the CPU
Goal: Give each process the impression it alone is actively using the CPU.
| Resource | Sharing Strategy |
|---|---|
| CPU | Time sharing |
| Memory | Space sharing (later) |
| Disk | Space sharing (later) |
Lecture Note
Time sharing on the physical CPU means processes take turns: A, B, A, B, A… Each process thinks it has its own virtual CPU. Memory and disk use space sharing — each process gets its own region.
Process States
stateDiagram-v2
running --> ready : deschedule
ready --> running : schedule
running --> blocked : I/O issued
blocked --> ready : I/O complete
- Running: On the CPU (only one on a uniprocessor)
- Ready: Waiting for the CPU
- Blocked: Asleep — waiting for I/O or synchronization to complete
Lecture Note
When B is running, A sits in the ready state. The scheduler picks from the ready queue.
OS must track every process in the system:
- Each process identified by unique Process ID (PID)
OS maintains queues of all processes:
- Ready queue: Contains all ready processes
- Event queue: One logical queue per event
- e.g., disk I/O and locks
- Contains all processes waiting for that event to complete
Limited Direct Execution
Direct Execution
- Allow user process to run directly on hardware
- OS creates process and transfers control to starting point (i.e.,
main())
Problems with Direct Execution
- Process could do something restricted — could read/write other process data (disk or memory)
- Process could run forever (slow, buggy, or malicious) — OS needs to be able to switch between processes
- Process could do something slow (like I/O) — OS wants to use resources efficiently and switch CPU to other process
Solution: Limited direct execution — OS and hardware maintain some control.
Problem 1: Restricting Execution
How can we ensure user process can’t harm others?
Solution: privilege levels supported by hardware (bit of status)
- User processes run in user mode (restricted mode)
- OS runs in kernel mode (not restricted)
- Instructions for interacting with devices
- Could have many privilege levels (advanced topic)
How can a process access a device?
- System calls (function call implemented by OS)
- Change privilege level through syscall trap instruction
What User Processes Cannot Do
User processes are not allowed to perform:
- General memory access
- Disk I/O
- Special x86 instructions like
lidt
If a process tries to do something restricted, the hardware generates a fault/exception.
How System Calls Work
- Process P wants to call
read()— but P can only see its own memory because of user mode (other areas, including kernel, are hidden) - P cannot call kernel code directly — instead it uses a syscall trap instruction
- The
read()library function executes:movl $6, %eax; syscall$6is the syscall-table index identifying which system call to invokesyscallis the trap instruction that calls through the trap table
- The
syscallinstruction switches to kernel mode — now the kernel can access all memory - The kernel follows entries in the trap table to the correct system call handler (e.g.,
sys_read) - The kernel can access user memory to fill in the user buffer
- Return-from-trap at end to return to Process P (back in user mode)
Problem 2: How to Take CPU Away?
OS requirements for multiprogramming (or multitasking):
- Mechanism — to switch between processes
- Policy — to decide which process to schedule when
Separation of Policy and Mechanism
Reoccurring theme in OS:
- Policy: Decision-maker to optimize some workload performance metric
- Which process when?
- Process Scheduler (future lecture)
- Mechanism: Low-level code that implements the decision
- How?
- Process Dispatcher (this lecture)
Dispatch Mechanism
OS runs a dispatch loop:
while (1) {
run process A for some time-slice
stop process A and save its context
load context of another process B
}
Lecture Note
The stop + save + load is called a context switch. Each process runs for a time slice (e.g., A, B, A, B…).
Two key questions:
- How does the dispatcher gain control?
- What execution context must be saved and restored?
Q1: How Does the Dispatcher Get Control?
Option 1: Cooperative Multi-tasking
- Trust process to relinquish CPU to OS through traps
- Examples: System call, page fault (access page not in main memory), or error (illegal instruction or divide by zero)
- Provide special
yield()system call
- Problem: Processes can misbehave
- By avoiding all traps and performing no I/O, can take over entire machine
- Only solution: Reboot!
- Not performed in modern operating systems
Option 2: True Multi-tasking
- Guarantee OS can obtain control periodically
- Enter OS by enabling periodic alarm clock
- Hardware generates timer interrupt (CPU or separate chip)
- Example: Every 10ms
- User must not be able to mask timer interrupt
- Dispatcher counts interrupts between context switches
- Example: Waiting 20 timer ticks gives 200 ms time slice
- Common time slices range from 10 ms to 200 ms
Q2: What Context Must Be Saved?
Dispatcher must track context of process when not running:
- Save context in process control block (PCB) (or, process descriptor)
What information is stored in PCB:
- PID
- Process state (i.e., running, ready, or blocked)
- Execution state (all registers, PC, stack ptr)
- Scheduling priority
- Accounting information (parent and child processes)
- Credentials (which resources can be accessed, owner)
- Pointers to other allocated resources (e.g., open files)
Lecture Note
The PCB is a struct (e.g.,
struct proc { pid, status, ... }) that holds everything the OS needs to know about a process.
Requires special hardware support:
- Hardware saves process PC and PSR on interrupts
Context Switch Procedure
sequenceDiagram
participant Program as Program
participant HW as Hardware
participant OS as Operating System
Note over Program: Process A running...
HW->>HW: timer interrupt
HW->>HW: save regs(A) to k-stack(A)
HW->>HW: move to kernel mode
HW->>OS: jump to trap handler
OS->>OS: Handle the trap
OS->>OS: Call switch() routine
OS->>OS: save regs(A) to proc-struct(A)
OS->>OS: restore regs(B) from proc-struct(B)
OS->>OS: switch to k-stack(B)
OS->>HW: return-from-trap (into B)
HW->>HW: restore regs(B) from k-stack(B)
HW->>HW: move to user mode
HW->>Program: jump to B's IP
Note over Program: Process B running...
Lecture Note
A timer interrupt (or syscall trap) causes hardware to save registers to the kernel stack and switch to kernel mode. The OS then performs a software context switch — saving A’s registers to A’s PCB and restoring B’s from B’s PCB. Finally, return-from-trap restores B’s registers from B’s kernel stack and jumps to B in user mode.
Summary
- Virtualization: Context switching gives each process the impression it has its own CPU
- Direct execution makes processes fast
- Limited execution at key points ensures OS retains control
- Hardware provides a lot of OS support:
- User vs kernel mode (privilege bit)
- Timer interrupts
- Automatic register saving and return-from-trap
Related
- Navigation: ← Lecture 1 · Lecture 3 →
- Exam: Midterm 1
- Course: CS 537 Map of Content