204 lines
6.1 KiB
Markdown
204 lines
6.1 KiB
Markdown
# Exception
|
|
|
|
An Exception is a **transfer of control** to the OS kernel in response to some event(like div by 0, overflow, ctrl+C). that is change in processor state.
|
|
|
|
**Exception Tables**
|
|
|
|
Each type of event has an unique exc number `k`: `k` is index into **exception table(interrupt vector table)**
|
|
|
|
Handler `k` is called each time exception `k` occurs.
|
|
|
|
## Asyncronous exceptions
|
|
|
|
It is caused by external events. Handler returns to next instruction.
|
|
|
|
for example: Timer interrupt, I/O interrupt.
|
|
|
|
## Syncronous exceptions
|
|
|
|
It is caused by events that occur as a result of exxecuting an current instruction.
|
|
|
|
* Traps
|
|
* Intentional like procedure calls (e.g. system calls)
|
|
* Returns to next instruction
|
|
* Faults
|
|
* Unintentional but possibly recoverable (e.g. page fault(recoverable), protection fault(not recoverable), floating point exception)
|
|
* re-executes by kernel or aborts
|
|
* Aborts
|
|
* Unintentional and not recoverable (e.g. illegal instruction, parity error, machine check)
|
|
* Aborts the program
|
|
|
|
## System Calls
|
|
|
|
Each x86-64 system call has a unique syscall number.
|
|
|
|
| Num | Name | Desc |
|
|
| --- | ------ | --------------- |
|
|
| 0 | read | read file |
|
|
| 1 | write | write file |
|
|
| 2 | open | open file |
|
|
| 3 | close | close file |
|
|
| 4 | stat | get file status |
|
|
| 57 | fork | create process |
|
|
| 59 | execve | execute program |
|
|
| 62 | kill | send signal |
|
|
|
|
## Fault Example
|
|
|
|
### Page Fault
|
|
```c
|
|
int a[1000];
|
|
main() {
|
|
a[500] = 13;
|
|
}
|
|
```
|
|
In this situation, a page containing `a[500]` is currently on disk, so page fault occurs, CPU cannot find the data in physical RAM. So kernel copy page from disk to memory, and return and re-executes the instruction `movl`
|
|
|
|
### Invalid Memory Ref
|
|
|
|
```c
|
|
int a[1000];
|
|
main() {
|
|
a[5000] = 13;
|
|
}
|
|
```
|
|
|
|
In this situation, address `a[5000]` is invalid, so protection fault occurs, kernel terminates the program by sending `SIGSEGV` signal to the user process. Then user process exits with error code `Segmentation Fault`.
|
|
|
|
|
|
## Process
|
|
|
|
An instance of a running program.
|
|
|
|
Process provides each program with two key abstractions:
|
|
* Logical control flow
|
|
* Each program seems to have **exclusive use of the CPU** provided by **context switching** of the kernel
|
|
* Private address space
|
|
* Each program seems to have **exclusive use of main memory** provided by **virtual memory** of the kernel
|
|
|
|
But in reality, computer runs multiple processes simultaneously by time-sharing CPU and multiplexing memory.
|
|
|
|
### Multiprocessing
|
|
|
|
Single processor executes multiple processes concurrently. process execution interleaved by time-slicing. Address spaces managed by virtual memory system. And register values for non-executing processes saved in memory.
|
|
|
|
Multicore processor share main memory each can execute a separate process. scheduling of processors onto cores done by kernel.
|
|
|
|
### Concurrent Processes
|
|
|
|
Concurrency is **not at the exact same time**.
|
|
|
|
Two processes are **concurrent** if their flows **overlap in time**. Otherwise, they are **sequential**.
|
|
|
|
Control flows for concurrent processes are pysically disjoint in time. But user think that they are logically running in parallel.
|
|
|
|
* Execution time of instruction may vary because of the Nondeterminism of the System: OS scheduling, Interrupts, Cache miss or Page fault, I/O device delays.
|
|
|
|
### Context Switching
|
|
|
|
Prcess are managed by a shared chunk of memory-resident OS code called the **kernel**.
|
|
|
|
What is important is that the kernel is **not a seprate process**. It is invoked by processes when they need OS services, or when exceptions occur. That is Part of the processor.
|
|
|
|
Control flow passes via a context switching.
|
|
|
|
## Syscall Error Handling
|
|
|
|
On error, Linux sys level function typically returns `-1` and sets the global variable `errno` to indicate the specific error.
|
|
|
|
Hard and fast rule:
|
|
* You must check the return status of every system-level function
|
|
* Only exception is the handful of functions that return void
|
|
|
|
Error reporting functions:
|
|
```c
|
|
void unix_error(char *msg) {
|
|
fprintf(stderr, "%s: %s\n", msg, strerror(errno));
|
|
exit(0);
|
|
}
|
|
```
|
|
|
|
Error handling wrappers:
|
|
```c
|
|
pid_t Fork(void) {
|
|
pid_t pid;
|
|
if ((pid = fork()) < 0) unix_error("Fork error");
|
|
return pid;
|
|
}
|
|
```
|
|
|
|
## Creating and Terminating Processes
|
|
|
|
* `pid_t getpid(void)` returnes pid of current process
|
|
* `pid_t getppid(void)` returns pid of parent process
|
|
|
|
We can think of a process as being in one of three states:
|
|
* Running
|
|
* Executing or waiting to be executed
|
|
* Stopped
|
|
* Process execution is suspended and will not be scheduled until futher notice
|
|
* Terminated
|
|
* Stopped permanently
|
|
|
|
### Terminating Processes
|
|
|
|
1. `return` from `main`
|
|
2. call `exit(status)` function
|
|
3. Receive a termination signal
|
|
|
|
```c
|
|
void exit(int status);
|
|
```
|
|
|
|
### Creating Process
|
|
|
|
Parent process can creates a new running child process by calling `fork()` system call.
|
|
|
|
```c
|
|
int fork(void);
|
|
```
|
|
|
|
it returns `0` to the newly created child, and returns **child's pid** to the parent.
|
|
Child is almost identical to parent: child get an identical copy of the parent's virtual address space, file descriptors, and process state.
|
|
But child has its own unique pid.
|
|
|
|
```c {cmd=gcc, args=[-O2 -x c $input_file -o 9_1.out]}
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
int main() {
|
|
pid_t pid;
|
|
int x = 1;
|
|
pid = fork();
|
|
if (pid == 0) { /* Child */
|
|
printf("child: x=%d\n", ++x);
|
|
exit(0);
|
|
}
|
|
|
|
printf("parent: x=%d\n", --x);
|
|
exit(0);
|
|
}
|
|
```
|
|
|
|
```sh {cmd}
|
|
while ! [ -r 9_1.out ]; do sleep .1; done; ./9_1.out
|
|
```
|
|
|
|
Concurrent execution of parent and child processes. `fork` duplicates but separates address space.
|
|
File descriptors are shared between parent and child like `stdout`, `stderr`.
|
|
|
|
Modeling fork with Process Graphs
|
|
* Each vertex represents a process state
|
|
* Directive Edges represent is ordering of execution.
|
|
* Edge can be labeled with current value of variables
|
|
|
|
Any topological sort of the graph corresponds to a feasible total ordering.
|
|
|
|
|
|
### Reaping Child Processes
|
|
|
|
When a child process terminates, it becomes a **zombie** until its parent calls `wait` to read its exit status.
|
|
|
|
## execve
|
|
|