Date post: | 29-Dec-2015 |
Category: |
Documents |
Upload: | megan-sherman |
View: | 227 times |
Download: | 2 times |
1
Operating Systems
Processes
Process Concept
• Process – a program in execution; process execution progress in sequential fashion
Program vs. Process
• Program is passive entity stored on disk (executable file), process is active – Program becomes process when executable file
loaded into memory• Execution of program started via GUI mouse
clicks, command line entry of its name, etc• One program can be several processes
– Consider multiple users executing the same program
Process Context/Image
Consists of• The address space of the process
– The program code, also called text section– Stack containing temporary data
• run-time stack of activation records (function parameters, return addresses, local variables)
– Data section containing global variables, statics, and constants
– Heap containing memory dynamically allocated during run time
5
Process Context/Image• And process’ current activity
– Current values of registers: general registers, PC, SP, PSW, segmentation registers (limit, base)
– Other information:• open files table, status of ongoing I/O• process status (running, ready, blocked), user id, ...
6
Memory Layout of a Process
data
Code/Text
Heap
Free space
Stack
CPU
Memory
PSW
Program Counter
Stack Pointer
Process States (1)
Three states a process may be in:
1. Running (actually using the CPU at that instant).
2. Ready (runnable; temporarily stopped to let another process run).
3. Blocked (unable to run until some external event happens).
Tanenbaum & Bos, Modern Operating Systems: 4th ed., Global Edition (c) 2015
Pearson Education Limited. All rights reserved.
Process States (2)
A process can be in running, blocked, or ready state. Transitions between these states are as shown.
Tanenbaum & Bos, Modern Operating Systems: 4th ed., Global Edition (c) 2015 Pearson Education Limited. All rights reserved.
blocked statecat file1 file2 file3 | grep test
• grep process is blocked (waits) until input is available from the pipe (output of cat is written to pipe)
• Or, a process may explicitly suspend itself
• pause()
Process Model
The lowest layer of a process-structured operating system handles interrupts and scheduling. Above that layer are
sequential processes.
Tanenbaum & Bos, Modern Operating Systems: 4th ed., Global Edition (c) 2015 Pearson Education Limited. All rights reserved.
Context Switch
• A CPU can execute one process at a time• In a multiprogramming environment the
CPU switches from one process to another for brief periods of time.
• When CPU switches to another process, the system must save the state of the old process and load the saved state for the new process via a context switch
• Context of a process is represented in the Process control block
12
Keeping Track of Processes
• For each process, OS maintains a data structure, called the process control block (PCB). The PCB provides a way of accessing all information relevant to a process:– This data is either contained directly in the PCB, or
else the PCB contains pointers to other system tables. • All current processes (PCBs) are stored in a
system table called the process table. – Either a linked list or an array, of PCB’s.
Process Control Block(PCB)
Some of the fields of a typical process table entry.
Tanenbaum & Bos, Modern Operating Systems: 4th ed., Global Edition (c) 2015 Pearson Education Limited. All rights reserved.
Process Representation in Linux
Represented by the C structure task_struct
pid t_pid; /* process identifier */ long state; /* state of the process */ unsigned int time_slice /* scheduling information */ struct task_struct *parent; /* this process’s parent */ struct list_head children; /* this process’s children */ struct files_struct *files; /* list of open files */ struct mm_struct *mm; /* address space of this process */
Process Scheduling
• Process scheduler selects among available processes for next execution on CPU
• Maintains scheduling queues of processes– Job queue – set of all processes in the system– Ready queue – set of all processes residing in
main memory, ready and waiting to execute– Device queues – set of processes waiting for
an I/O device
16
When are processes created?
• System initialization – many daemons(background processes) for
processing email, printing, web pages etc.– Shell (foreground)
• Execution of a process creation system call by a running process (fork or CreateProcess)
• User request to create a new process (type a command or click an icon)
List of all active processes: ps (Unix), Ctl-Alt-Del (Windows)
17
When are processes terminated?• Normal exit (voluntary)
– Done its job– exit() in UNIX, ExitProcess() in Windows, GUI based
• Error exit (voluntary)– Process discovers a fatal error itself and exits with an error code– E.g. cp file1 file2, when file1 does not exist
• Fatal error (involuntary), due to bugs– E.g. divide by zero, referencing illegal memory
• Killed by another process (involuntary)– By executing kill(..) system call in Unix– Killer process needs authorization (e.g. the root)
18
Creating processes in UNIX
• A Unix process is created by another.– a newly created process is the “child” of the “parent”
process that created it– every process has exactly one parent– a process may create any number of child processes
• processes have a unique PID (process ID)– index to the PCB in the process table
• Processes are created in UNIX with the fork() system call.
19
Process Hierarchies
• Processes form a hierarchy– UNIX calls this a process group
• Signals can be sent to all processes of a group
• Windows has no concept of process hierarchy– all processes are created equal
20
init
• At the root of the family tree of processes is the special process init:– created as part of the bootstrapping procedure– pid = 1– among other things, init spawns a child to listen
to each terminal, so that a user may log on (login processes).
– If login successful, executes a shell to start accepting commands
– do "man init” to learn more about it
A typical tree of processes in Linux
Process Control
To list the complete information for all active processes in the system ps –ef
To list your processes ps
Process Control
When the shell has to wait for a process to finish before giving you another prompt, that process is in the foreground
A background process is one that runs independently of the parent shell The shell doesn't have to wait for the process to finish The shell gives you a prompt immediately and you can execute another
command To run a command in the background:
command & The shell will display the job number and PID of the background process
and then display the prompt Any output of the background process that is sent to stdout will appear on
the terminal, intermixed with the foregound process you will probably want to redirect the process‘ output
Process Control
When a process is in the background, you can't use <ctrl>c to stop it Only foreground processes will recognize keyboard input
You must use the kill command kill <pid>
If the kill command is ignored, then use the -9 option kill -9 <pid>
We can control whether a process should continue in the foreground or background From background to foreground
fg <job number> From foreground to background
<ctrl>z to suspend the foreground process bg to send it to the background
If a background process needs input, the shell will stop the job You must then bring it to the foreground to enter the input
Creating a process in UNIX
We need some mechanism to instruct the system to create a new process fork system call
When fork( ) is used, the OS generates a copy of the calling process The original process is the parent process The copy is the child process Execution in the two IDENTICAL processes continues from the point of the
fork( ) The child process inherits all variables, values, open files, current directory,
environment variables, etc. from the parent The child is assigned a unique PID The parent's fork returns the child's PID The child's fork returns 0 There is no guarantee which process, parent or child, will enter the CPU first
fork()
pid = fork()
if (pid!=0) {
//parent code}
else {
// child code}
fork() example: fork_ex1.c
#include <stdio.h>#include <unistd.h>
main() { int pid; printf("I am the original process with PID %d and PPID %d.\n", getpid(), getppid()); pid = fork(); /* child and parent continue from here */
if (pid != 0) { /* parent code */ printf("I am the parent process with PID %d and PPID %d.\n", getpid(), getppid()); printf("my child's PID is %d\n", pid); } else { /* child code */ printf("I am the child process with PID %d and PPID %d.\n", getpid(), getppid()); }
printf("PID %d terminates.\n", getpid());}
output
> g++ -o ex1 fork_ex1.c
> ./ex1
I am the original process with PID 25643 and PPID 25592.
I am the parent process with PID 25643 and PPID 25592.
my child's PID is 25644
PID 25643 terminates.
I am the child process with PID 25644 and PPID 25643.
PID 25644 terminates.
getpid, getppid, getpgid, setpgid
pid_t getpid() Returns the PID of the calling process
pid_t getppid() Returns the calling process’ parent’s PID If parent needs child processes’ PIDs they must be saved when the children are
forked. Process groups
Every process belongs to a group The parent process is the process leader of all its children processes The leader's pid will also be the process group id (PGID) The PGID allows the OS to send signals to groups of processes
pid_t getpgid(pid_t pid); Returns the process group ID of the process whose PID is equal to pid Returns the process group ID of the calling process if pid is 0
int setpgid(pid_t pid, pid_t pgid); Sets the process group ID of the process with PID pid to pgid
fork_ex2.c
/* count the number of hees, has and hos *//* then remove newline characters try again */
#include <stdio.h>#include <sys/types.h>#include <unistd.h>
main() { fork(); printf("hee\n"); fork(); printf("ha\n"); fork(); printf("ho\n");}
Output (with newline, output not buffered)
> g++ -o ex2 fork_ex2.c> ./ex2heehaheehohahahahohohohohohoho>
Output without newline (buffered)
Buffer is flushed when full, or when file is closed. newline forces flush to stdout Buffers are inherited by child process Output:
heehahoheehahoheehahoheehahoheehahoheehahoheehahoheehaho
Open files
Every process is given a file descriptor table Every open file of a process is assigned an index into this table called the
file descriptor When a child process is forked, it receives a COPY of its parent's file
descriptor table This includes where the parent is in each open file
The file pointer offset That is, the child starts reading from the same point If one of them reads from a such an open file, the read/write pointer is
advanced for both of them.
Getting file Information int stat(const char *filename, struct stat *buf) int stat(int filedes, struct stat *buf)
Returns the information for the given filename/file descriptor in the stat struct The stat struct:
struct stat { mode_t st_mode; /* Protection */ ino_t st_ino; /* Inode number */ dev_t st_dev; /* ID of device containing */ /* a directory entry for this file */ nlink_t st_nlink; /* Number of links */ uid_t st_uid; /* User ID of the file's owner */ gid_t st_gid; /* Group ID of the file's group */ off_t st_size; /* File size in bytes */ time_t st_atime; /* Time of last access */ time_t st_mtime; /* Time of last data modification */ time_t st_ctime; /* Time of last file status change */ /* Times measured in seconds since */ /* 00:00:00 UTC, Jan. 1, 1970 */ long st_blksize; /* Preferred I/O block size */ blkcnt_t st_blocks; /* Number of 512 byte blocks allocated*/
}
stat_ex.c#include <stdio.h>#include <sys/types.h>#include <sys/stat.h>#include <unistd.h>
main(int argc, char *argv[]) { struct stat buff;
if (argc > 1 ) { if (stat(argv[1], &buff) != -1) { printf("The size in bytes of %s is:", argv[1]); printf("%d\n", buff.st_size); } else { perror(argv[1]); return 1; } } else { printf("Usage: %s filename\n", argv[0]); return 2; } return 0; //successful}
Handling error
When a system call or library function fails, it usually returns a -1 It also assigns a value to an external variable errno
By examining errno, you can determine the cause of the failure errno always contains the value of the last failed call A list of error values, their defined constants, and a short explanation of the
error can be found in /usr/include/sys/errno.h To include this header file in your program, use #include <errno.h>
perror system call Used to capture the description of any error It takes one argument - a pointer to a char (string s) It prints the string s followed by a colon and a blank, then an error message
and a new line See errno_ex.c
Current Directory
char *getcwd(char *buf, size_t size); The getcwd() function (not system call) copies an absolute pathname of
the current working directory to the array pointed to by buf, which is of length size.
If the current absolute path name would require a buffer longer than size elements, NULL is returned, and errno is set to ERANGE
Going someplace new int chdir(const char *path);
chdir changes the current directory to that specified in path. What do you think happens when a child process executes a chdir -
does this effect the parent?
/* Testing the chdir() function*/
#include <stdio.h>#include <unistd.h>#include <sys/param.h>main( ){ int pid;
printf( "Before forking, my directory is: %s\n", getcwd(NULL, MAXPATHLEN+1) ); pid = fork(); if ( pid != 0 ) { sleep( 5 ); printf( "Parent's directory is: %s\n", getcwd(NULL, MAXPATHLEN+1) ); } else { chdir( "/usr/include" ); printf( "child's directory is: %s\n", getcwd(NULL, MAXPATHLEN+1) );
}}
output
>a.outBefore forking, my directory is: /home/fatalay/CSC310child's directory is: /usr/includeParent's directory is: /home/fatalay/CSC310
exec()
When you use the shell to run a command (say ls), the shell will execute fork( ) to get a new process running
How then does the shell get ls to run in the child process? The child process is just a copy of the shell - which is certainly NOT
the ls utility
Use an exec( ) system call or library function During an exec the current process image is overlaid with the
command image The text, data, and stack segments are replaced with the new code Signals that were being caught in the original process are reset to
their default action
If successful, exec does NOT return since the original code is lost The new program begins executing at main (if a C, C++, or Java
program)
exec family
5 library functions Execl, execlp, execv, execvp, execle
1 system call Execve All library functions call the system call execve
execlp, execvp are the most commonly used.
execl and execlp
execl library function int execl(const char *path, const char *arg, ...); path is the absolute or relative path name of the command arg0 the name of the command arg1 - argn are the null terminated strings representing arguments to
the command argn must be NULL
execlp library function int execlp(const char *file, const char *arg, ...); file is the absolute or relative path name of the command
PATH will be searched if the first character is not a /
execv and execvp
execv library function int execv(const char *path, char *const argv[]); path is the absolute or relative path name of the command argv is an array of pointers to null-terminated strings that represent the
arguments to the command argv[0] should be the name of the command arg[n] must be NULL
execvp library function int execvp(const char *file, char *const argv[]); file is the absolute or relative path name of the command
PATH will be searched if the first character is not a /
execl() example
#include <stdio.h>#include <unistd.h>
main(){ printf("I'm process %i and I'm about to exec an ls -l\n", getpid()); execl("/bin/ls", "ls", "-l", NULL); /* Execute ls */ printf("This line should never be executed.\n");}
> ./execl_ex
I am process 7168 and I am about to exec an ls -l
total 44
-rw-r--r-- 1 fatalay sjufacul 506 Feb 16 23:12 chdir_ex.c
-rwxr-xr-x 1 fatalay sjufacul 6492 Feb 16 23:48 execl_ex
-rw-r--r-- 1 fatalay sjufacul 183 Feb 16 23:48 execl_ex.c
-rw-r--r-- 1 fatalay sjufacul 563 Feb 10 00:11 fork_ex1.c
execvp example
See execvp_ex.c #include <stdio.h>
#include <unistd.h>
main(int argc, char* argv[]){ fprintf(stdout, "Parent is about to fork child\n"); if (fork() == 0) /* child */ { fprintf(stdout, "Child process is about to exec\n"); execvp(argv[1], &argv[1]); /* execute other program */ fprintf(stderr, "This line should never print\n"); fprintf(stderr, "Could not execute %s\n", argv[1]); } fprintf(stdout, "Parent is about to terminate\n");}
Output
> ./execvp_ex ls -l
Parent is about to fork child
Parent is about to terminate
Child process is about to exec
> total 62
-rw-r--r-- 1 fatalay sjufacul 506 Feb 16 23:12 chdir_ex.c
-rw-r--r-- 1 fatalay sjufacul 935 Feb 10 00:12 errno_ex.c
-rwxr-xr-x 1 fatalay sjufacul 6572 Feb 16 23:52 execl_ex
-rw-r--r-- 1 fatalay sjufacul 247 Feb 16 23:52 execl_ex.c
-rwxr-xr-x 1 fatalay sjufacul 7136 Feb 17 15:22 execvp_ex
-rw-r--r-- 1 fatalay sjufacul 1150 Feb 17 15:22 execvp_ex.c
-rw-r--r-- 1 fatalay sjufacul 563 Feb 10 00:11 fork_ex1.c
argv[1]
Process Termination
Process executes last statement and then asks the operating system to delete it using the exit() system call. void exit(int status) //include <stdlib.h> Returns status data from child to parent
0: success, nonzero: failure If parent is executing a wait(), it is notified of child’s exit status is made available to parent If the parent is not waiting, the child's status will be made available
to it when the parent subsequently executes wait( ) Process’ resources are deallocated by operating system Exit flushes all output streams and closes all open streams
File descriptors are closed A SIGCHLD is sent to the parent process The PPID of all of its child processes is set to 1 (init)
Status
It is stored as an integer Assuming a 32-bit integer: The high-order 16 bits are zero
Normal termination – Byte 1 contains the exit code (0 - 255) – Byte 0 contains zeros
Termination because of an un-caught signal – Byte 1 contains zeros – Byte 0 contains the signal number
byte 3 byte 2 byte 1 byte 0
0 0 exitcode 0
wait()
The wait( ) system call pid_t wait(int *status); Include:
#include <sys/types.h> #include <sys/wait.h>
This call will suspend the parent process until any of its child processes terminates Then the wait call returns and the parent process can continue
The return value from wait Child is present - the terminating child's PID No child present - -1
If a process has one or more zombie children, wait returns immediately with the status of one of the zombies
status is a pointer to a location that will receive the child's exit status information
wait_ex.c /* This program demonstrates the wait system call
and the status returned by the child process*/
#include <stdio.h>#include <stdlib.h>
main(){ int pid, status, childPid;
printf("I'm the parent process and my PID is %i\n", getpid()); pid = fork(); if (pid != 0) /* parent */ { printf("I'm the parent process with PID %i and PPID %i\n“, getpid(), getppid()); childPid = wait (&status); /* wait for child to terminate */ printf("A child with PID %i terminated with exit code %i\n“, childPid, status >> 8); printf(" Parent - PID %i terminates\n", getpid()); } else { printf("I'm the child process with PID %i and PPID %i\n“, getpid(), getppid()); printf(" Child - PID %i terminates\n", getpid()); exit( 15 ); }
}
Output
I'm the parent process and my PID is 22580
I'm the parent process with PID 22580 and PPID 22553
I'm the child process with PID 22581 and PPID 22580
Child - PID 22581 terminates
A child with PID 22581 terminated with exit code 15
Parent - PID 22580 terminates
52
How shell executes a command
when you type a command, the shell forks a clone of itself the child process makes an exec call, which causes it to stop
executing the shell to replace the process’ memory space with a new program
the parent process, still running the shell, waits for the child to terminate
fork wait
exitexec Required job
Parent shell
Child
waitpid()
waitpid( ) system call pid_t waitpid(pid_t pid, int *status, int options); pid specifies what to wait for
pid < -1 Wait for a child whose GID is equal to the absolute value of pid
pid = -1 Wait for any child to finish - same behavior as wait( )
pid = 0 Wait for a child whose GID is the same as the calling process
pid > 0 Wait for child whose PID equals pid
status is the same as for wait( ) options allows you to specify that a call to waitpid( ) should not suspend
the parent process if no child process is ready to report its exit status
Example
See waitpid_ex.c Output
> ./waitpid_ex
I'm the parent process and my PID is 22664
I'm the parent process with PID 22664 and PPID 22553
I'm the first child process with PID 22665 and PPID 22664
I'm the second child process with PID 22666 and PPID 22664
Child2 - PID 22666 terminates
Child1 - PID 22665 terminates
A child with PID 22665 terminated with exit code 15
Parent - PID 22664 terminates
Zombies and Orphans
When a child process exits, it is not immediately cleared off the process table
Instead, a signal (SIGCHLD) is sent to its parent process The parent needs to acknowledge its child's death using a wait( ) system
call Only then is the child process completely removed from the system In the time between the child's exit and the parent's acknowledgment, the
child process is in a state called zombie When the parent process is not properly coded, the child remains in the
zombie state A zombie process does not take up many resources, but it does use up a
PID To see zombie proceses
ps -ef | grep defunct
Zombie process (from wikipedia)
When a process ends, all of the memory and resources associated with it are deallocated so they can be used by other processes.
However, the process's entry in the process table remains.
The parent is sent a SIGCHLD signal indicating that a child has died; the handler for this signal will typically execute the wait system call, which reads the exit status and removes the zombie.
The zombie's process ID and entry in the process table can then be reused.
However, if a parent ignores the SIGCHLD, the zombie will be left in the process table.
Orphans
When a process exits, if it had any child processes, they become orphans Who will then accept the child's SIGCHLD signal? An orphan process is automatically adopted by the init process (PID 1) and
becomes a child of this init process Thus when the child terminates, it does not turn into a zombie init is properly written to acknowledge the death of its child processes
Example
See zombie_ex.c Output> ./zombie_ex &
[1] 22823
> ps
PID TTY TIME CMD
22553 pts/19 0:00 tcsh
22543 pts/19 0:00 csh
22824 pts/19 0:00 zombie_e
22825 pts/19 0:00 ps
22823 pts/19 0:00 zombie_e
> ps -ef |grep defunct
fatalay 22827 22553 0 20:37:19 pts/19 0:00 grep defunct
fatalay 22824 22823 0 - ? 0:00 <defunct>
> kill -9 22823
> ps -ef | grep defunct
fatalay 22830 22553 0 20:37:38 pts/19 0:00 grep defunct
parent
Avoiding zombies
To avoid creating zombie processes, the parent must:
1. Handle the SIGCHLD signal.
2. In this signal handling function, the parent must wait for the child process.
We will explore signals as an interprocess communications (IPC) mechanism shortly.