Process: A Context for Computation A process is largely defined by: UNIX Process Control • Its CPU state (register values). Bach 7 • Its address space (memory contents). • Its environment (as reflected in Operating Systems Course operating system tables). Hebrew University Spring 2007 Process Creation Bach 7.1 Process layout #include <sys/types.h> #include <unistd.h> pid_t fork(void); • System call: – Child - 0. – Parent - PID of the child. • System call algorithm: – Allocate a slot in process table. – Allocate PID. – Create a logical copy of the parent context. – Return values. Stack for Boot Process RET addr 1 Before calling fork() a i Fork Example 42 RET addr 2 z void f (int x) SP { if ( (pid = fork()) < 0 ) int z; Before fork() fork(); error } If (pid == 0) void g() { Unsued Stack { code for child } char a; int i; else f (42); RET addr 2 } { code for parent } int main() { g(); RET addr 1 return 0; }
Stack for Boot Process RET addr 1 After calling fork() a Example: Race Conditions i 42 RET addr 2 #include <iostream> z void f (int x) SP #include <unistd.h> { #include <sys/types.h> int z; RET addr 1 fork(); a Location 3 int main() } i { Child SP 42 pid_t pid; RET addr 2 void g() z if ((pid = fork()) < 0 ) Stack for new Process { exit(1); //error char a; if(pid != 0) { int i; for(int i = 0; i < 100; i++) f (42); RET addr 2 cout<<"Parent process "<< i <<endl; } } else { for(int i = 100; i < 200; i++) int main () cout <<"Child process "<< i << endl; { } g(); RET addr 1 return 0; return 0; } } Process Termination Normal Process Termination Bach 7.3 #include <stdlib.h> • Normal Termination: void exit (int status); – Executing a return from the main function. • System call: – Calling the exit function. (ANSI C) – Status: IPC. – Calling the _exit function. (Sys call) – NEVER returns. • Abnormal Termination: • System call algorithm: – When a process receives certain signals. – Mask Signals. – Close open files. – Release memory. – Save the process exit status. – Set the process state to ZOMBIE. Awaiting Process Termination Orphans and Zombies Bach 7.4 • When a child exits when its parent is not currently executing a wait(), a zombie #include <sys/types.h> emerges. #include <sys/wait.h> – A zombie is not really a process as it has pid_t wait(int *status); terminated but the system retains an entry in the process table. • System call: – A zombie is put to rest when the parent finally executes a wait(). – Returns the PID of a zombie child -1 when no children exist. – Status is the exit status of the child process. • A child process whose parent has terminated is referred to as orphan . – Wait can block the caller until a child process terminates. • When a parent terminates, orphans and zombies are adopted by the init process • System call algorithm: – Search for a zombie child of the process. ( prosess-id:0 ) of the system. – Extract PID and status of the zombie child. – Release the process table slot.
notable exec properties Invoking other programs Bach 7.5 • an exec call transforms the calling • The exec invokes another program, process by loading a new program in its overlaying the memory space with a memory space. copy executable file. • the exec does not create a new sub- • The contents of the user-level context is process. accessible through exec parameters. • unlike the fork there is no return from a successful exec. exec(filename, argv, envp); System call algorithm Exec example • Determine the file properties If((pid = fork()) < 0) – Determine If the file is an executable. error; – Determine if the user has permissions. if (pid== 0 ){ – Determine the file’s layout. exec( arguments ); • Copy exec arguments to system space. exit(-1); • Detach old memory regions. } • Allocate new regions. • Copy exec arguments. // parent continues here fork/wait/execv Example The Shell #include <iostream> #include <unistd.h> Bach 7.8 #include <sys/wait.h> using namespace std; int main() • The shell read a command line from { int x = 42; STDIN and execute. pid_t pid; if ((pid = fork()) < 0 ) • The shell has to main commands: exit(1); if(pid != 0) { – Internal commands. (cd) int status; cout << "Parent process. x=" << x << endl; – External commands. (cp) wait (&status); } else { • External commands may run cout << "Child process. x=" << x << endl; char* args[] = {"ls", NULL}; foreground/background. execv ("/bin/ls", args); cout << "Never reached" << endl; } return 0; }
Signals Sending Signals Bach 7.2 • Signals are notifications sent to a process in Using the keyboard: order to notify the process of events. – Ctrl-C: Causes the system to send an INT – Kernel. signal ( SIGINT ) to the running process. – Processes (system call kill) Using shell kill command: • The kernel send a signal by setting a bit in the field of the process table entry. – The kill command has the following format: kill [options] pid • A process can remember different types of signals, but not the number of signals from each type. Non-Catchable Signals Handling Signals • Most signals may be caught by the process, but there are a few signals that the process cannot • The kernel handles signals in the context catch, and cause the process to terminate. of the process that receives them so – For example: KILL and STOP . • If you install no signal handlers of your own the process must run to handle signals. runtime environment sets up a set of default signal • There are three case for handling handlers. signals: – For example: • The default signal handler for the TERM – The process exits. (default action) signal calls the exit(). – The process ignores. • The default handler for the ABRT is to dump – The process execute particular function. the process's memory image into a file, and then exit. oldfun = signal(signum,newfun); Summary Signal Handlers - Example 1. Each signal may have a signal handler, which is a function that gets called when the #include <stdio.h> process receives that signal. #include <unistd.h> #include <signal.h> 2. When the signal is sent to the process, the operating system stops the execution of the void catch_int(int sig_num) { process, and "forces" it to call the signal signal(SIGINT, catch_int); //install again! handler function. printf("Don't do that\n"); fflush(stdout); 3. When that signal handler function returns, } the process continues execution from wherever it happened to be before the signal int main(int argc, char* argv[]) { was received, as if this interruption never signal(SIGINT, catch_int); occurred. for ( ;; ) pause();//wait till receives a signal. }
Avoiding Signal Races - Masking Signals • The occurrence of a second signal while the signal handler function executes. – The second signal can be of different type than the one being handled, or even of the same type. • The system also contains some features that will allow us to block signals from being processed. – A global context which affects all signal handlers, or a per-signal type context.
Recommend
More recommend