Files
2025-02-SystemProgramming/notes/9.md
2025-11-26 03:47:12 +09:00

6.1 KiB

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

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

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:

void unix_error(char *msg) {
    fprintf(stderr, "%s: %s\n", msg, strerror(errno));
    exit(0);
}

Error handling wrappers:

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
void exit(int status);

Creating Process

Parent process can creates a new running child process by calling fork() system call.

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.

#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);
}
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