Processes
Running Dynamic Code
Basic function of OS is to execute and manage code dynamically
- Command line terminal
- Icon double click
- Jobs/tasks run as part of a batch system
Programs
- An executable file in long-term storage (e.g. chrome.exe)
Processes
- The basic unit of a program in execution
- The running instantiation of a program, stored in RAM
- One-many relationship = One programs can call many processes
PCB: Process Control Block
PCB: Process Control Block = TCB: Task(or Thread) Control Block
- Kernel data structure representing a process
- The loader create PCB for each process
- The kernel must manage new process
- Has at least one thread
- Keeps track of the memory used by the process
= Processes have address space
- Control flow = Address space = Thread
- Change of IP = Change of Control flow
- Keeps runtime state of the process
Process States
- new: Being created
- running: Being executed
- waiting: Waiting for some event to occur
- ready: Waiting to be assigned to a processor
- terminated: Finished execution

IO is slow
→ Though scheduling is done, IO can't be executed
→ By giving it waiting state, Do not include in the schedule target
Parents and Children
- All processes have parents
= Processes are made by process
- If a process spawns other processes, they become it's children
- If a parent exits before its children, the children become orphans
- If a child exits before the parent calls wait(), the children becomes a zombie
- Zombie processes return compute resources, but do not return PIDs so that PID remians in the Process Table
- e.g.) Parent exit()
→ Parent can't wait() for the child
→ Child becomes orphan
→ Child becomes zombie
Process Tree
- init(systemd in LINUX) is a special process started by the kernel (pid=1)
- e.g.) Let process A is a parent of the process B
- A is terminated
- B becomes orphan
- B becomes zombie
- B becomes a child of the init
- B is terminated
Additional Execution Context
- File descriptors
- stdin, stdout, stderr, Sockets, Pipes
- Permissions
- User and group and others
- Access to specific APIs
- Shared Resources
Exapmle: UNIX
UNIX Process Management
fork()
- Create a copy of the current process (NO arguments)
- Return 2 same processes
- Parent has non-zero pid (the child's pid)
- Child has pid 0
- Implementation
- Create and initialize PCB in the kernel
- Create a new address space
- Initialize the address space with a copy of the address space of the parent
- Modern OS does not copy directly,
Copy when exec() is not in the code
- Inherit the execution context of the parent
- Inform the scheduler that the new process is ready
exec(Program path)
- Change the program(= code data) being run by the current process
- Implementation
- Load the new program into the current address space
- Copy command line arguments into memory
- Initialize the hardware context to start execution
- EIP = Entry point in the ELF header
- ESP = A newly allocated stack
wait(PID)
- Wait for a process to finish
- If
wait() doesn't exist, then no guarantee which one will be executed first
signal()
- Send a notification to another process
abort(PID) can be used for parent process to immediately end a child process
Context Switching
Context switching
- Save state of a process before a switching
- Restore original process state when switching back
Process Stack
Each process has a stack in memory that stores
- Local variables
- Arguments to functions
- Return addresses from functions
On x86
- Stack grows downwards
- ESP points to the bottom of the stack
- EBP points to the base of the current frame
- Instructions push, pop, call, ret, int, iret modify the stack
Ex)
int bar(int a, int b) {
int r = rand();
return a + b - r;
}
int foo(int a) {
int x, y;
x = a * 2;
y = a - 7;
return bar(x, y);
}
int main(void) {
…
foo(12);
…
}
In AT&T syntax
- Registers are prefixed with %,
- The left is source and the right is destination
- mov %eax, %ebx (eax -> ebx)
In Intel syntax
- The left is destination and the right is source
- mov ebx, eax (ebx <- eax)
Call foo() & Store return addr to main()

Store EBP of previous func (main())

Allocate address space of current func foo()

Store local vars and args

Call bar() & Store return addr to foo()

Store EBP of previous func foo()

Allocate address space of current func bar()

Leave = Deallocation of the current func bar()
- mov esp, ebp
- pop ebp
- Return value is placed in EAX

Ret = EIP <- ESP

Stack Switching
Stack holds
- local vars
- args to functions
- return addr
A process's control flow is stored on the stack
However, stack doesn't hold register vals
Switching between processes
- switch()
- Process 1 calls into switch() routine
- push eax ~ edx
- CPU registers are pushed onto the stack (of Process 1)
- mov [cur_esp], esp
- Stack pointer is saved into memory (ESP for Procees 1)
- mov esp, [saved_esp]
- Stack pointer for process 2 is loaded
- pop edx ~ eax
- CPU registers are restored (of Process 2)
- ret
- switch() returns back to process 2
Switches into a process by return from a function
Switches out of a process by calling into a function
About new processes
A new process doesn't have a stack
→ Pretend there was a previous call
- Build a fake initial stack frame
- looks exactly like the instruction just before main() called into switch()
- When switch() return, run main() of the new process
When do we switch processes?
Voluntary yielding
- Processes must voluntary give up control by calling an OS API
- Problems
- Misbehaving or buggy apps may never yield = may never context switch
- No guarantee that apps will yield in a reasonable amount of time
- Wasteful CPU resources (e.g.) Process is waiting on I/O)
Switch during API calls to the OS
- When a process calls an OS API, OS has an opportunity to context switch
- Problems
- Misbehaving or buggy apps may never yield = may never context switch
- Some normal apps don't use OS APIs for long periods
Switch on I/O
- When a process is waiting on I/O, switch to another process
- Problems
- Some normal apps don't have any I/O for long periods
Preemptive Context Switching = Switch based on a timer interrupt
- Use a timer interrupt to force context switching at set intervals
= Limit the maximum running time of process
- If it's been running for some max duration (scheduling quantum),
the handler switches to the next process
- Problems
- Requires hardware support (a programmable timer)
Isolation
Process Isolation
We can execute multiple processes concurrently
Problem: How do we stop process from behaving badly?
- Overwritting kernel memory
- Reading/writing data from other processes
How to implement execution with limited privilege?
- Use an interpreter or a simulator
- Execute each program instruction in a simulator (e.g. Java)
- If the instruction is permitted, do the instruction
- However, they are slow
- So, Run the unprivileged code directly on the CPU
Protected Mode
x86 CPUs support three rings with different privileges
- Ring 0: OS kernel
- Ring 1, 2: device drivers
- Ring 3: userland
Real vs Protected
- CPU starts in 16-bit real mode
- Protected mode is disabled
- Bootloader switches CPU to protected mode
mov eax, cr0
or eax, 1
mov cr0, eax
Dual-Mode Operation
- Ring 0
- kernel/supervisor mode
- Full privileges of the hardware
- Ring 3
- user mode or userland
- Limited privileges
Privileged Instructions
- Examples
- sti/cli - Enable and disable interrupts
- Modifying the CR0 registers
- hlt - halt the CPU
- If a user program attempts to execute a privileged instruction
- General protection exception gets thrown by the CPU
Changing Modes
Applications often need to access the OS
But the OS is ring 0, apps are ring 3
How do apps get access to the OS?
- Apps invoke system calls with an interrupt (e.g. int 0x80)
- int causes a mode transfer from ring 3 to ring 0
Mode Transfer
Userland
- Application executes trap (int) instruction
- EIP, CS, EFLAGS are pushed onto the stack
- Mode switches from ring 3 to ring 0
Kernel mode
- Save the state of the current process
- Locate and execute the syscall handler
- Restore the state of process
- Place the return value in EAX
- Use iret to return to the process
- Switch back to the original mode
Example
- Software executes int 0x80
- CPU transfers execution to the OS handler
- Look up the handler in the IVT
- Switch from ring 3 to 0
- OS executes the system call
- Save the process state
- Use EAX to locate the system call
- Execute the system call
- Restore the process state
- Put the return value in EAX
- Return to the process with iret
- Pop EIP, CS and EFLAGS
- Switches from ring 0 to 3