Lecture 3



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

Context Switch

Etc

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:

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.**

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

ShortcutOutputSignalNumberNotes
⌃ Z (1)Pause a jobSIGTSTP20Also known as suspending a job
⌃ Z (2)Continue a jobSIGCONT18Pressing ⌃Z again will continue a process that was just suspended
^ CInterrupt a jobSIGINT2Tell a process that it should not continue, the most common way to end a program
⌃ \Quit a jobSIGQUIT3Similar 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

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.

  1. Save the current processor state
  2. Load the state for interrupt handling
  3. Invoke the corresponding Interrupt Service Routine (ISR)
  4. 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

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.

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.

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.

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.

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

  1. Consider two mode switch cases: user -> kernel and kernel -> 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.

  2. 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

  1. What do hardware interrupts and software interrupts (traps) have in common?

    1. Both require a mode-switch from user-mode to kernel-mode, provided that the operating system is currently executing instructions in user-mode.
  2. What are the differences between hardware interrupts and software interrupts (traps)?

    1. 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.

    2. 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

  1. If a local variable is declared in an interrupt handler (ISR), where will it be stored?

    The variable will be stored in kernel stack

  2. 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:


Question 6

  1. 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.

  1. List 2 feasible and 1 infeasible outputs of running this code
HC
HP
CT
HP
HC
CT
CT
HP
HC