lecture source: 14-ecf-procs.pdf 15-ecf-signals.pdf
A program is sequence of instrucions (Say I{n}). Also, their respective adresses form a incrementing sequence a{n}. The instruction I{k} loaded at some address a{i} will move the program counter to a{j} after execution, and the CPU will execute the instruction I{k+1} loaded at that address. This flow of programs is called control flow. If j = i+1, (i.e. Ik moves program counter to next adress) we say the flow through Ik is smooth; otherwise, it is abrupt.
- smooth - add, ...
- abrupt - jmp, call, ret
If you don't need a kernel, i.e. if your program can execute directly on hardware without the need for an intermediary, exceptional control flow becomes unnecessary because it is only required to allow the kernel to intervene in a currently running program.
It is part of abrupt control flow, however does not control by the program's instructions. Instead, control is switched to kernal code and handled by it.
-
Exceptions - triggered by
something
, handled byhandler
, which is kernal routine loaded in boot-time.- Interrupts - triggered by h/w events. (like keyboard input)
- Traps - triggered by certain instruction on user code,
syscall
- Faults - triggered by error conditions that a handler might able to correct.
- Aborts - triggered by unrecoverable fatal errors. (like detatch the RAM or something ...)
-
Context switch - Process scheduling
process
is an abstraction that allows to kernal controls bunch of diffrent executables.
-
Signals - How processes communicate with each other. (like Ctrl-C on shell)
- Transfer of control to the OS kernel in response to some event
- Events - Divide by 0, arithmetic overflow, page fault, I/O request, typing Ctrl-C ...
- Exception Tables
- Each type of event has a unique exception number k.
- k = index into exception table (a.k.a. inturrupt vector)
- Handler k is called each time exception k occurs.
- Exception Table and handlers are loaded to memory on boot-time.
- When exception occurs on instructions Icurr, it returns to Icurr or Inext or does not returns(abort).
- Caused by events external to the processer. (e.g. keyboard pressed, Timer interrupt, ...)
- Event occured (cpu's inturrupt pin goes high)
- Icurr executed (Note; even if an event occurs while Icurr running, an exception occurs after Icurr completes execution.)
- Read exception number from system bus.
- Call to inturrupt handler. (When this, adress to Inext pushed to kernel stack)
- After handler executed, it returns to Inext.
- Caused by execution of instruction
syscall
. - Kernal provide procedure-like services such as
read
- read a filefork
- create new processexecve
- load a new program to current processexit
- terminate the current process
- For programmer's perspective, it is identical to regular call
- However they are executed on
kernel mode
, notuser mode
- Returns control to next instruction of
syscall
.
mov $0x2, %eax # syscall ID 2 is open
syscall # Return value in %rax
cmp $0xfffffffffffff001,%rax
- Result from error conditions that a handler might able to correct.
- able to correct - Returns to faulting execution and re-execute it!
- disable - Abort
Example
- Page Fault (recoverable)
- The process accesses not-loaded adress. (or instruction itself has been not-loaded yet)
- Page fault handler loads current page to memory from disk.
- The handler returns to Icurr & re-execute it!
- More explaination on VM part..
- Segmentation Fault (Abort)
- The process accesses to illigal adress
- Segmentation fault handler delivers SIGSEGV to process.
- The Process terminated (or Signal handler for SIGSEGV executed, if it is planted for that process..)
- Result from unrecoverable fatal errors.
- always abort
- EX) Memory bits are corrupted, ...
- process - instance of running program.
- Key abstractions provided by process
- Logical control flow - context switching
- Each program seems to have exclusive use of the CPU
- Private adress space - virtual memory
- Each program appears to have exclusive access to the main memory
- Two processes run concurrently if their flows overlap in time (Otherwise, they are sequential)
Implements For process control. (See 5_ShellLab/shlab-handout/tsh.c also.)
-
Process states
- Running - Either executing or chosen to execute by kernel.
- Stopped - The execution is suspended and will not be scheduled until further notice(by signals).
- Terminated - Stoped permanently.
-
Process become terminated for one of three reasons:
- Receiving a signal whose default action is to terminate.
- Returning from the
main
routine
- The return value become the exit status.
- Calling the
exit
function
void exit(int status)
- Terminates with an exit status of
status
- Normal return status is 0, nonzero on error.
- Called once, never returns.
- Terminates with an exit status of
-
Parent process creates a new running child process by calling
fork
int fork(void)
- Returns 0 for child process, child's PID to parent process.
- Called once, returns twice.
- Child executes concurrently with its parent. - cannot predict order.
- Duplicate but separate address space
- Shared open files
- Example
int main()
{
pid_t pid;
int x = 1;
if((pid = fork()) == -1) {
perror("fork: ");
exit(1);
} else if (pid == 0) { /* Child */
printf("child: x=%d\n", ++x);
exit(0);
}
printf("parent: x=%d\n", --x);
exit(0);
}
Result
linux> ./fork
parent: x=0
child: x=2
-
track the unpredictable cocurrent execution with process graph
-
Reaping child processes
-
zombie process - A process that has terminated but still consumes system resources.
- Exit status, various OS tables, ...
- These system resources are freed by Reaping it from its parent.
-
Reaping
- Performed by parent calling syscalls. (
wait
,waitpid
) - Parent given exit status information.
- Kernal then deletes zombie child (child process terminated -> reap by its parent -> kernal frees system resources using by child)
- If any parent terminates without reaping a child, then the orphaned child will reaped by
init
process. - Only need explicit reaping in long-running processes.
- shells, servers, ...
- Performed by parent calling syscalls. (
-
int wait(int *child_status)
- Suspends current process until one of its children terminates. (and reaps that terminated children!)
- Return
pid
of the child process that terminated - If
child_status
is non-NULL
, then the integer it points to will be set to a value that indicates reason the child terminated and the exit status. (seewait(2)
)
-
pid_t waitpid(pid_t pid, int &status, int options)
wait
with various options rather than just suspends current process until one of its children.
-
-
Loading and Running Programs
int execve(char *filename, char *argv[], char *envp[])
- Loades executable
filename
(ELF or script with#!interpreter
) in the current process - ...with argument list
argv
(passe to loaded program) - ...and environment variable list
envp
- "name=value" strings (e.g.
PATH=/bin:/usr/local/bin
) - gloval variable
char **environ
on libc. - see
getenv(3)
,putenv(3)
,printenv(3)
.
- "name=value" strings (e.g.
- Loades executable