Dual Mode
For any program, the process can spawn from it is identical whether it spawns in user-mode or in kernel-mode.
Mode Switch v. Context Switch
Mode Switch
- User -> Kernel
- user makes a sys call
- an interrupt happens
- an exception
- Kernel -> User
- new process starts
- new thread starts
- return from interrupt
- return from exception
- finished up doing a sys call
- When you're done start a new process
- UNIX signal (user level upcall)
Context Switch
- Must save state into PCB
- Then load state into PCP
- Then continue execution
Etc
If a context switch happens, it wasn't necessarily also a mode switch
Sometimes there's a mode switch without a context switch
Sometimes there's a mode switch and a context switch
A context switch can cause a mode switch
Hardware Rings
Rings vs. Modes
Each ring supports one mode. Four rings, four modes, in the simplest case, just two.
Privileged Instructions
Privileged instructions are only available in kernel mode, if these instructions are attempted by a user-level process, an exception is thrown and the process is terminated. This is an example of a processor exception, which is distinct from a programming language exception
What is the difference between a processor exception and a programming language exception?
When a program is running, if an exception happens, it is handled by language runtime in user-land. A processor exception, on the other hand, causes the processor to immediately transfer control to the kernel, to the exception handler, inside the system.
Exception handling facilities provided by the operating system
Unix-like operating systems provide facilities for handling exceptions in programs via IPC. Typically, interrupts caused by the execution of a process are handled by the interrupt service routines of the operating system, and the operating system may then send a signal to that process, which may have asked the operating system to register a signal handler to be called when the signal is raised, or let the operating system execute a default action (like terminating the program). Typical examples are SIGSEGV, SIGBUS, SIGILL and SIGFPE.
Examples of privileged instructions:
- Changing which memory locations are accessible to a user process
- Reading, writing, or sending commands to/from I/O devices
- Disabling interrupts
- Jumping into kernel mode
Interrupts
An operating system is an event driven creature. It responds to things that happen on its machine, and reacts correspondingly. It responds to syscalls, but other things, such as clock ticks, and initialization of drivers.
Question: One of the ways in which the OS gets notified of an event is using the "polling" technique. What is the disadvantage with this technique? What technique do modern computers use to circumvent it?
Answer: Polling periodically checks each device to see if it needs service. This wastes precious resources like the processor time Modern computers use interrupts as an alternative to circumvent it. Using interrupts, an I/O device only notifies the processor when it needs attention. Upon receiving the signal from the device, the CPU enters the interrupt handler and performs any necessary operations.**
An interrupt is a signal, a request generated by either a device or a program, which is sent to the operating system
Software interrupts may be unexpectedly triggered by program execution errors. These interrupts typically are called traps or exceptions. For example, a divide-by-zero exception will be "thrown" (a software interrupt is requested) if the processor executes a divide instruction with divisor equal to zero. These are a form of synchronous interrupt.
Hardware interrupts are asynchronous signals sent by devices (such as a drive, a keyboard, or a timer), to the CPU, which then sends that signal to the operating system. This includes a hard drive, as well as hardware clocks.
There are two types of asynchronous interrupts, maskable and unmaskable
- maskable interrupts
- non-maskable interrupts: Unable to be disabled. On Intel, there are two pins, INTR and NMI.
The signal from the device is sent through a specified pin to the processor.
PIC: programmable interrupt controller
There's a separate kernel stack for each process
On a multi-processor environment, each processor has its own interrupt listeners & handlers
Question: How does the processor know what code to run?
Answer: It has an interrupt vector, set up by the kernel, which has an address stored by the processor register, and code executed in kernel mode will only start at specific well-defined location, known as entry points.
A user-level upcall, in UNIX, is known as a signal.
The difference between a signal and an interrupt, is that interrupts are mediated by the processor and handled by the kernel while signals are mediated by the kernel (possibly via system calls) and handled by processes. The kernel may pass an interrupt as a signal to the process that caused it (typical examples are SIGSEGV, SIGBUS, SIGILL and SIGFPE).
Signals
Ranked from weakest to strongest
| Shortcut | Output | Signal | Number | Notes |
|---|---|---|---|---|
| ⌃ Z (1) | Pause a job | SIGTSTP | 20 | Also known as suspending a job |
| ⌃ Z (2) | Continue a job | SIGCONT | 18 | Pressing ⌃Z again will continue a process that was just suspended |
| ^ C | Interrupt a job | SIGINT | 2 | Tell a process that it should not continue, the most common way to end a program |
| ⌃ \ | Quit a job | SIGQUIT | 3 | Similar to an interrupt, but a little stronger (can still be caught), and will produce a core dump. The strongest of the signals that can be called via keyboard shortcuts |
UNIX Signals
Various signals can be sent in UNIX to interact with a program. Many of these contain keyboard shortcuts, but first it is important to go over the most common types of signals. Programs can customize how they react to various signals by catching, handling, or ignoring them.
To view all signals, type $ trap -l
To view all signal keyboard shortcuts, type $ stty -e or $ stty all
Signal Definitions
SIGTERM (15): Tells a program to stop, in order to allow the program to handle its termination gracefully. Can be caught, handled, or ignored.
SIGINT (2): Used to interrupt a program that is running. It is the same as the SIGTERM signal, but it explicitly refers to an interruption that was called from the terminal. Can be caught, handled, or ignored.
SIGQUIT (3): Similar to SIGTERM but it will generate a core dump. Can be caught, handled, or ignored.
SIGSTOP (17): Temporarily stop a program. Cannot be caught, handled, or ignored.
SIGTSTP (18): Sends the program a signal, telling it to temporarily stop. Unlike SIGSTOP, it can be caught, handled, or ignored.
Handling Interrupts
- interrupt handler
an interrupt handler , also known as an interrupt service routine or ISR , is a special block of code associated with a specific interrupt condition. Interrupt handlers are initiated by hardware interrupts, software interrupt instructions, or software exceptions, and are used for implementing device drivers or transitions between protected modes of operation, such as system calls.
Although there's truly many, many steps to handling an interrupt, at a high level, it consists of four main components.
- Save the current processor state
- Load the state for interrupt handling
- Invoke the corresponding Interrupt Service Routine (ISR)
- Resume the program execution
It's important to note that interrupts can be preempted. A maskable interrupt can be underway, but could then be interrupted by a non-maskable interrupt. Or, to serve an interrupt, something else might be required. An exception is being handled, but then we look for something that is currently not in memory, and needs to be loaded in from storage, so we would need to invoke a syscall to load the necessary data into memory.
xv6 Interrupts
- 0 to 31 reserved by Intel for processor exceptions
- 32 to 47 are configurable, used for device interrupts
- 64 used for system call interrupt
- On Linux, 128 (0x80) is used for system calls
- xv6 interrupt handler entries
vector.S(generated byvectors.pl, a Perl script)
A process doesn't solely exist in user mode, so the address space of the kernel is mapped in the memory of every single process. For this reason, it has a user-mode context as well as a separate kernel-mode context, which means there is a user-space stack, and also a separate kernel-space stack, used when executing kernel mode, such as during syscalls. For this reason, it is possible to have a mode switch without a context switch.
A process id (PID) is stored in the process control block (PCB), is inaccessible
to the corresponding user-level process, but can be requested using the
getpid() syscall.
Handling Syscalls
There is a user stub and a kernel stub
When the process initially begins running, its user-stack will store things like functions, but the kernel stack will be empty. Once the thread is interrupted, however, the user CPU state will be loaded into its corresponding kernel stack. When it is waiting for I/O, or waiting for a syscall to return, the user stack will contain the context to resume when the syscall returns, and the kernel stack will contain the context to be returned when I/O completes.
Process Management
Most operating systems allow a user process to create another process through the use of a system call.
- Windows uses
createProcess(), one big syscall, which creates the process, sets up the environment, and starts up the program - UNIX-like systems have *separate syscalls
fork(): creates a processopen(),close(), anddup(): sets up the environmentexec(): loads the program image, and starting execution
init is the first process that spawns when the operating system first spins
up. For this reason, it is assigned the PID value 1. All processes become
descendents of init. Whenever a user logs in, a new proces will be created for
that user. Each user can create their own browser for their processes. Each of
these processes can spawn child processes, which can spawn child processes, and
so on.
If a process is destroyed, (for instance, because it crashed), some operating
system will begin destroying its children. In UNIX, however, init becomes the
new parent for that process.
fork: creates a copy of the current process, known as the parent process, and starts that copy, which is known as the child process
Checking if the active process of the most recent fork() is the child or the
parent requires a bit of trickery, because fork() is called once, but it
returns twice.
```c
pid_t pid = fork();
if (pid == 0) {
printf("child\n");
}
else {
printf("parent\n");
}
```
Up to 64 processes can be active at once in the xv6 operating system.
exec: changes the data and program (text section) being run by the current process, substituting the new program in place of the current process. It does not create a new process.wait: waits for a process to finish. It blocks the caller, the parent process, and does so until one of its child process terminates. If it has no child processes, or it forks a background process,waitreturns immediately.waitcan optionally be passed the PID of a child of this parent as a parameter.exit: indicate that a process is finished and ready to terminate.
Executable and Linkable Format (ELF)
The ELF format defines the structure for binaries, libraries, and core files. The formal specification allows the operating system to interpreter its underlying machine instructions correctly. ELF files are typically the output of a compiler or linker and are a binary format.
The executable image file loaded by exec must be in a particular format.
- xv6 uses the ELF format
Zombie Process
On Unix and Unix-like computer operating systems, a zombie process or defunct process is a process that has completed execution (via the exit system call) but still has an entry in the process table: it is a process in the "terminated state".
This occurs for the child processes, where the entry is still needed to allow the parent process to read its child's exit status: once the exit status is read via the wait system call, the zombie's entry is removed from the process table and is said to have been "reaped".
A child process always becomes a zombie before being removed from the resource table. In most cases, under normal system operation zombies are immediately waited on by their parent and then reaped by the system -- processes that stay zombies for a long time are generally an error and cause a resource leak, but the only resource they occupy is the process table entry -- process ID.
Orphan Processes
An orphan process is a computer process whose parent process
has finished or terminated, though it remains running itself. In a
Unix-like operating system any orphaned process will be
immediately adopted by the special init system process: the kernel
sets the parent to init.
An orphan can be performing useful operations on the computer, it simply has no parent.
This operation is called re-parenting and occurs automatically. Even though
technically the process has the init process as its parent, it is still called
an orphan process since the process that originally created it no longer exists.
In other systems orphaned processes are immediately terminated by the kernel. In
modern Linux systems, an orphan process may be reparented to a "subreaper"
process instead of init.
If a parent does not call wait, then it will become a zombie, it's a warning
from xv6 that the parent process did not call wait.
Questions
Question 1
A: The kernel services can be invoked by 3 any program.
B: Privileged instructions may be executed by 1 only the kernel
C: An application that needs to access an I/O device could not be written
without 2, kernel functions, though library functions make it more convenient
to do so
D: The kernel can execute 2 both privileged and non-privileged instructions.
Question 2
Consider two mode switch cases:
user -> kernelandkernel -> user. For each mode, list events that cause the mode switch.A mode-switch from user-mode to kernel-mode will occur if a syscall is made, a trap is triggered, a processor exception, or a hardware interrupt occurs.
A mode-switch from kernel-mode to user-mode will occur when a syscall is fully processed, an interrupt was fully handled, or a new process is initialized.
Will a context switch always cause a mode switch? Why or why not?
A context switch may not necessarily cause a mode switch. For example, the operating system could switch contexts from one kernel-mode process to another kernel-mode process. A switch between a user-mode process, and another different separate user-mode process, on the other hand, will cause a mode switch as well.
Question 3
What do hardware interrupts and software interrupts (traps) have in common?
- Both require a mode-switch from user-mode to kernel-mode, provided that the operating system is currently executing instructions in user-mode.
What are the differences between hardware interrupts and software interrupts (traps)?
A trap is synchronous, and operates internal to the CPU. Hardware interrupts are asynchronous, will be sent to the CPU before they are handled by the operating system.
All software interrupts can be ignored by the operating system, but a non-maskable interrupt, exclusive to hardware interrupts, cannot be ignored by the operating system.
Question 4
If a local variable is declared in an interrupt handler (ISR), where will it be stored?
The variable will be stored in kernel stack
How does the process coordinate between the user stack and the kernel stack?
The process itself does not coordinate between the user stack and the kernel stack. Coordination between these two stacks is performed entirely by the operating system.
Question 5
Consider a coffee shop where customers can order coffee by phone. Find the best match for the coffee shop analogy:
- The system is (4) the coffee shop
- The process is (2) the customer
- The interrupt is (1) the telephone ringing
- The CPU is (5) the coffee machine
- A system call is (3) placing an order
Question 6
- When will the last line be printed?
The last line will only be printed if the call to exec directly above it
fails, and returns an error.
- List 2 feasible and 1 infeasible outputs of running this code
HC
HP
CT
HP
HC
CT
CT
HP
HC