1 exceptional control flow Ⅱ. 2 outline kernel mode and user mode process context switches three...
DESCRIPTION
3 User and Kernel Modes Processes are managed by a shared chunk of OS code called the kernel –Important: the kernel is not a separate process, but rather runs as part of some user processTRANSCRIPT
1
Exceptional Control Flow Ⅱ
2
Outline
• Kernel Mode and User Mode• Process context switches• Three States of Processes• Context Switch• System Calls and Error Handling• Creating and Terminating Processes• Suggested reading 8.2, 8.3, 8.4
3
User and Kernel Modes
• Processes are managed by a shared chunk of OS code called the kernel– Important: the kernel is not a separate
process, but rather runs as part of some user process
4
Protection
• Restricts an application – to execute some instructions (privileged
instruction)– to access some portions of the address space
• In some control registers there typically is a mode bit– Kernel (supervisor) mode if the bit is set– User mode if the bit is clear
5
User and Kernel Modes
• Process running in kernel mode can – execute any instructions in the instruction set– can access any memory locations in the system
• Process running in user mode can– neither execute privileged instructions– nor directly reference code or data in the kernel
area of the address space– only do above indirectly via system call interface
6
User and Kernel Modes
• A process running application code – is initially in user mode– changes the user mode to kernel mode
• When the exception occurs and control passes to the exception handler
– changes the kernel mode to user mode• When control returns to the application code
• The only way for the process to change from user mode to kernel mode is via exception
7
Implementing the Process Abstraction
• Requires close cooperation between both– the low-level hardware and– the operating system software
8
Context switching
• The kernel maintains a context for each process
• The context is the state that the kernel needs to restart a preempted process
• Context contains– Value of PC, register file, status registers,
user’s stack, kernel’s stack– Kernel data structures
• Process table, page table, file table
9
Context switching
• The mechanism that performs the multitasking
• Higher level form of exceptional control flow– is built on top of the lower level exception
mechanism
10
Context switching
• The scheduler (a chunk of kernel code) does scheduling as following– Decides whether to preempt the current
process during the execution of a process – Selects a previously preempted process
(scheduled process) to restart– Preempts the current process
• Saves the context of the current process– Restarts the scheduled process
• Restores the saved context of the scheduled process
• Passes the control to this newly restored process
11
Three states of a process
• Running– The process is either executing on the CPU– or is waiting to be executed – and will eventually be scheduled.
• Stopped. – The execution of the process is suspended – and will not be scheduled.
• Terminated. – The process is stopped permanently.
12
Three states of a process
• A running process becomes stop– By receiving a signal such as
• SIGSTOP, SIGTSTP, SIGTTIN, or SIGTTOU
• A stopped process becomes running– By receiving a SIGCONT signal
13
Three states of a process
• A process becomes terminated– receiving a signal whose default action is to
terminate the process – returning from the main routine– calling the exit function
14
Context switching
15
Context switching
• When does the context switch happen?– The kernel is executing a system call on
behalf of the user such as• read, sleep which will cause the calling process
blocked• Even if a system call does not block, the kernel can
decide to perform a context switch rather than return control to the calling process
– As a result of an interrupt• Timer interrupt
16
Context switching
Process Acode
Process Bcode
user code
kernel code
user code
kernel code
user code
Timecontext switch
context switch
17
Error Handling
• Unix system-level functions encounter an error– typically return –1– set the global integer variable errno
• to indicate what went wrong
18
Error Handling
1 if ((pid = fork()) < 0) {2 fprintf(stderr, "fork error: %s\n", 3 strerror(errno));3 exit(0);4 }
1 void unix_error(char *msg) /* unix-style error */2 {3 fprintf(stderr, "%s: %s\n", 4 msg, strerror(errno));4 exit(0);5 }
19
Error Handling
1 if ((pid = fork()) < 0)2 unix_error("fork error");
1 pid_t Fork(void)2 {3 pid_t pid;45 if ((pid = fork()) < 0)6 unix_error("Fork error");7 return pid;8 }
20
Obtaining Process ID’s
• Process ID – PID– Each process has a unique positive PID
• Getpid()– Returns the PID of the calling process
• Getppid()– Returns the PID of its parent
• The process that created the calling process
21
Obtaining Process ID’s
• The getpid and getppid routines return an integer value of type pid_t
• pid_t– Defined in types.h as an int on Linux systems
#include <unistd.h>#include <sys/types.h>pid_t getpid(void);pid_t getppid(void);
returns: PID of either the caller or the parent
22
Exit Function
• The exit function terminates the process with an exit status of status.
#include <stdlib.h>void exit(int status);
this function does not return
23
Fork Function
• A parent process – creates a new running child process – by calling the fork function
#include <unistd.h>#include <sys/types.h>pid_t fork(void);
Returns: 0 to child, PID of child to parent, -1 on error
24
Fork Function
• The newly created child process is – almost, but not quite, identical to the parent.
• The parent and the newly created child have different PIDs.
Understanding fork
pid_t pid = fork();if (pid == 0) { printf("hello from child\n");} else { printf("hello from parent\n");}
Process npid_t pid = fork();if (pid == 0) { printf("hello from child\n");} else { printf("hello from parent\n");}
Child Process m
pid_t pid = fork();if (pid == 0) { printf("hello from child\n");} else { printf("hello from parent\n");}
pid = m
pid_t pid = fork();if (pid == 0) { printf("hello from child\n");} else { printf("hello from parent\n");}
pid = 0
pid_t pid = fork();if (pid == 0) { printf("hello from child\n");} else { printf("hello from parent\n");}
pid_t pid = fork();if (pid == 0) { printf("hello from child\n");} else { printf("hello from parent\n");}
hello from parent hello from childWhich one is first?25
26
Fork Function
• The child – gets an identical (but separate) copy of the
parent’s user-level virtual address space• including the text, data, and bss segments, heap,
and user stack. – also gets identical copies of any of the
parent’s open file descriptors• Which means the child can read and write any files
that were open in the parent when it called fork.
27
Fork Function
• Called once– In the parent process
• Returns twice: – In the parent process
• Return the PID of the child
– In the newly created child process.• Return 0
28
Fork Function
• The return value provides an unambiguous way – whether the program is executing in the
parent or the child.
29
Fork Function
• Concurrent execution– The parent and the child are separate
processes that run concurrently. – The instructions in their logical control flows
can be interleaved by the kernel in an arbitrary way.
– We can never make assumptions about the interleaving of the instructions in different processes.
30
Fork Function
1 #include "csapp.h"23 int main()4 {5 pid_t pid;6 int x = 1;78 pid = Fork();9 if (pid == 0) { /* child */10 printf("child : x=%d\n", ++x);11 exit(0);12 }1314 /* parent */15 printf("parent: x=%d\n", --x);16 exit(0);17 }
31
Fork Function
• Duplicate but separate address spaces– Immediately after the fork function returned
in each process, the address space of each process is identical.
• Local variable x has a value of 1 in both the parent and the child when the fork function returns in line 8.
32
Fork Function
• Duplicate but separate address spaces. – The parent and the child are separate
processes• they each have their own private address spaces. • Any subsequent changes that a parent or child makes
to x – are private – and are not reflected in the memory of the other
process.
33
Fork Function
• Duplicate but separate address spaces– The variable x has different values in the
parent and child when they call their respective printf statements.
• Shared files
Fork Example #2
void fork2(){ printf("L0\n"); fork(); printf("L1\n"); fork(); printf("Bye\n");}
• Both parent and child can continue forking
L0 L1
L1
ByeBye
ByeBye
34
Fork Example #3
• Both parent and child can continue forkingvoid fork3(){ printf("L0\n"); fork(); printf("L1\n"); fork(); printf("L2\n"); fork(); printf("Bye\n");} L1 L2
L2
ByeBye
ByeBye
L1 L2
L2
ByeBye
ByeBye
L0
35
Fork Example #4
• Both parent and child can continue forkingvoid fork4(){ printf("L0\n"); if (fork() != 0) {
printf("L1\n"); if (fork() != 0) { printf("L2\n"); fork();}
} printf("Bye\n");}
L0 L1
Bye
L2
Bye
ByeBye
36
Fork Example #5
• Both parent and child can continue forkingvoid fork5(){ printf("L0\n"); if (fork() == 0) {
printf("L1\n"); if (fork() == 0) { printf("L2\n"); fork();}
} printf("Bye\n");}
L0 Bye
L1
Bye
Bye
Bye
L2
37
38
Outline
• Reaping Child Processes• Putting Processes to Sleep• Suggested reading 8.4
39
Zombie
• The kernel does not remove a terminated process from the system immediately after the process terminates
• The process is kept around in a terminated state until it is reaped by its parent.
40
Zombie
• When the parent reaps the terminated child– the kernel passes the child’s exit status to the
parent, – and then discards the terminated process, at
which point it ceases to exist.
• A terminated process that has not yet been reaped is called a zombie.
linux> ./forks 7 &[1] 6639Running Parent, PID = 6639Terminating Child, PID = 6640linux> ps PID TTY TIME CMD 6585 ttyp9 00:00:00 tcsh 6639 ttyp9 00:00:03 forks 6640 ttyp9 00:00:00 forks <defunct> 6641 ttyp9 00:00:00 pslinux> kill 6639[1] Terminatedlinux> ps PID TTY TIME CMD 6585 ttyp9 00:00:00 tcsh 6642 ttyp9 00:00:00 ps
ZombieExample
• ps shows child process as “defunct”
• Killing parent allows child to be reaped by init
void fork7(){ if (fork() == 0) {
/* Child */printf("Terminating Child, PID = %d\n", getpid());exit(0);
} else {printf("Running Parent, PID = %d\n", getpid());while (1) ; /* Infinite loop */
}}
41
linux> ./forks 8Terminating Parent, PID = 6675Running Child, PID = 6676linux> ps PID TTY TIME CMD 6585 ttyp9 00:00:00 tcsh 6676 ttyp9 00:00:06 forks 6677 ttyp9 00:00:00 pslinux> kill 6676linux> ps PID TTY TIME CMD 6585 ttyp9 00:00:00 tcsh 6678 ttyp9 00:00:00 ps
NonterminatingChild Example
• Child process still active even though parent has terminated
• Must kill explicitly, or else will keep running indefinitely
void fork8(){ if (fork() == 0) {
/* Child */printf("Running Child, PID = %d\n", getpid());while (1) ; /* Infinite loop */
} else {printf("Terminating Parent, PID = %d\n", getpid());exit(0);
}}
42
43
Zombie
• If the parent process – terminates without reaping its zombie
children, – the kernel arranges for the init process to
reap them. • The init process
– has a PID of 1 – and is created by the kernel during system
initialization.
44
Zombie
• Long-running programs such as shells or servers should always reap their zombie children.
• Even though zombies are not running, they still consume system memory resources.
45
Wait_pid Function
#include <sys/types.h>
#include <sys/wait.h>
pid_t waitpid(pid_t pid, int *status, int options);returns: PID of child if OK, 0 (if WNOHANG) or -1 on error
46
Wait_pid Function
• pid > 0
– The wait set is the singleton child process • whose process ID is equal to pid
• pid = -1
– The wait set consists of all of the parent’s child processes
47
Wait_pid Function
• The calling process has no children– waitpid returns –1 – sets errno to ECHILD.
• If the waitpid function was interrupted by a signal– returns –1 – sets errno to EINTR.
48
Wait_pid Function
• options = 0– waitpid suspends execution of the calling
process until a child process in its wait set terminates
– If a process in the wait set has already terminated at the time of the call, then waitpid returns immediately
– waitpid returns the PID of the terminated child that caused waitpid to return
– the terminated child is removed from the system
49
Wait_pid Function
• options– WNOHANG: Return immediately (with a return
value of 0 ) if none of the child processes in the waiting set has terminated yet
– WUNTRACED: Suspended execution of the calling process until a process terminated or stopped child that caused the return
50
Wait_pid Function
• options– WUNTRACED | WNOHANG : Suspended
execution of the calling process until a process terminated or stopped child that caused the return. Also, return immediately (with a return value of 0 ) if none of the child processes in the wait set is terminated or stopped
51
Wait_pid Function
• Checking the exit status of a reaped child– The status argument is non-NULL– waitpid encodes status information about the
child • that caused the return in the status argument.
– The wait.h include file defines several macros
• for interpreting the status argument
52
Wait_pid Function
• WIFEXITED(status): – Returns true if the child terminated normally
• via a call to exit or a return.• WEXITSTATUS(status):
– Returns the exit status of a normally terminated child.
– This status is only defined if WIFEXITED returned true.
53
Wait_pid Function
• WIFSIGNALED(status): – Returns true if the child process terminated
because of a signal that was not caught• WTERMSIG(status):
– Returns the number of the signal that caused the child process to terminate.
– This status is only defined if WIFSIGNALED (status) returned true.
54
Wait_pid Function
• WIFSTOPPED(status): – Returns true if the child that caused the
return is currently stopped.• WSTOPSIG (status):
– Returns the number of the signal that caused the child to stop.
– This status is only defined if WIFSTOPPED (status) returned true.
55
Wait_pid Function
1 #include "csapp.h"2 #define N 234 int main()5 {6 int status, i;7 pid_t pid;89 for (i = 0; i < N; i++)10 if ((pid = Fork()) == 0) /* child */11 exit(100+i);12
56
Wait_pid Function
13 /* parent waits for all of its children to terminate */14 while ((pid = waitpid(-1, &status, 0)) > 0) {15 if (WIFEXITED(status))16 printf("child %d terminated normally with exit17 status=%d\n", pid,
WEXITSTATUS(status));18 else19 printf("child %d terminated abnormally\n", pid);20 }21 if (errno != ECHILD)22 unix_error("waitpid error");2324 exit(0);25 }
57
Wait_pid Function
unix> ./waitpid1
child 22966 terminated normally with exit
status=100
child 22967 terminated normally with exit
status=101
58
Wait_pid Function1 #include "csapp.h"2 #define N 234 int main()5 {6 int status, i;7 pid_t pid[N+1], retpid;89 for (i = 0; i < N; i++)10 if ((pid[i] = Fork()) == 0) /* child */11 exit(100+i);1213 /* parent reaps N children in order */14 i = 0;
59
Wait_pid Function
15 while ((retpid = waitpid(pid[i++], &status, 0)) > 0) {16 if (WIFEXITED(status))17 printf("child %d terminated normally with exit 18 status=%d\n", retpid, WEXITSTATUS(status));19 else20 printf("child %d terminated abnormally\n", retpid);21 }2223 /* The only normal termination is if there are no more children */24 if (errno != ECHILD)25 unix_error("waitpid error");2627 exit(0);28 }
60
Putting Process to Sleep
• Suspends a process for some period of time.• Returns zero if the requested amount of time
has elapsed• Returns the number of seconds still left to sleep
otherwise.
#include <unistd.h>unsigned int sleep(unsigned int secs);
returns: seconds left to sleepint pause(void);
always returns -1