Chapter 7 Process Management Part 2
Chapter 7 Process Management Part 2
5
Changing Priorities - Example
• In this program, the process executed ps commands before
and after a couple of nice() calls.
6
Changing Priorities - Example
• When the process’ priority value became nonzero, it was
flagged with an “N” by ps, together with the sh and ps
commands that it created due to the system() library call.
$_
8
Accessing User and Group IDs
• The system calls that allow you to read a process’ real and
effective IDs:
uid_t getuid()
uid_t geteuid()
gid_t getgid()
gid_t getegid()
11
Thread Management
• Four major functions make up the common
thread-management capabilities in most
implementations:
– Create: Create a thread.
– Join: Suspend and wait for a created thread to
terminate.
– Detach: Allow the thread to release its
resources to the system when it finishes and
not to require a join.
– Terminate: Return resources to the process. 12
Redirection
• When a process forks, the child inherits a copy of
its parent’s file descriptors.
• When a process execs, all nonclose-on-exec file
descriptors remain unaffected, including the
standard input, output, and error channels.
13
Redirection
• To perform the redirection, the shell performs the following
series of actions:
– The parent shell forks and then waits for the child shell to terminate.
– The child shell opens the file “ls.out”, creating it or truncating it as
necessary.
ls > ls.out
– The child shell then duplicates the file descriptor of “ls.out” to the
standard-output file descriptor, number 1, and the closes the
original descriptor of “ls.out”.
– The child shell then exec’s the ls utility.
– Since the file descriptors are inherited during an “exec()”, all of
the standard output of ls goes to “ls.out”.
– When the child shell terminates, the parent resumes.
• The parent’s file descriptors are unaffected by the child’s actions, as each process
14
maintains its own private descriptor table.
Redirection – Example
• This program that does approximately the same kind of
redirection as a UNIX shell does.
16
Disk Usage
• Disk usage - uses a novel technique for counting the number
of non-directory files in hierarchy.
• When the program is started, its first argument must be
the name of the directory to search.
• It searches through each entry in the directory, spawning
off a new process for each entry.
• Each child process either exits with 1 if its associated file
is a non-directory file, or repeats the process, summing
up the exit codes of its children and exiting with the total
count.
• This creates a large number of processes, which is not
particularly efficient.
17
Disk Usage - Example
#include <stdio.h>
#include <sys/file.h>
#include <sys/dir.h>
#include <sys/stat.h>
long processFile();
long processDirectory();
main( argc, argv )
int argc;
char* argv[];
{
long count;
count = processFile( argv[1] );
printf(“Total number of non-directory files is %ld \n”, count );
return ( /* EXIT_SUCCESS */ 0 );
}
18
Disk Usage - Example
19
Disk Usage - Example
21
Disk Usage - Example
$-
22
Signals
• Program must sometimes deal with unexpected or
unpredictable events, such as :
– a floating point error
– a power failure
– an alarm clock “ring”
– the death of a child process
– a termination request from a user ( i.e., Control-C )
– a suspend request from a user ( i.e., Control-Z )
Signal Process
#8
24
Signals
• Any process can send any other process a signal, as long
as it has permission to do so.
• A programmer may arrange for a particular signal to be
– ignored or
– processed by a special piece of code called a signal handler.
25
Signals
• Signals are defined in
“/usr/include/sys/signal.h”.
• The default handler usually performs one of the
following actions:
– terminate the process and generate a core file (dump)
– terminate the process without generating a core image
file (quit)
– ignore and discard the signal (ignore)
– suspend the process (suspend)
– resume the process
26
List of Signals
• Here’s a list of the System V predefined signals, along with
their respective macro definitions, numerical values, and
default actions, as well as a brief description of each:
27
List of Signals
Macro # Default Description
28
List of Signals
Macro # Default Description
29
Terminal Signals
• The easiest way to send a signal to a
foreground process is by pressing Control-C or
Control-Z from the keyboard.
• When the terminal driver (the piece of software
that supports the terminal) recognizes that
Control-C was pressed, it sends a SIGINT signal
to all of the processes in the current
foreground job.
• Similarly, Control-Z causes it to send a SIGTSTP
signal to all of the processes in the current
foreground job.
30
Requesting an Alarm Signal: alarm()
• The default handler for the SIGALRM signal displays the
message “Alarm clock” and terminates the process.
• Here’s how alarm() works:
unsigned int alarm( unsigned int count )
32
Handling Signals: signal()
• signal() allows a process to specify the action that
it will take when a particular signal is received.
• It has the following syntax:
void(*signal(int sigCode, void (*func)(int))) (int)
35
Handling Signals: signal() - Example
• Some changes are made to the previous program so that it catches and
processes the SIGALRM signal efficiently
• The program uses a user-defined signal handler, “alarmHandler()” which
uses signal()
37
Protecting Critical Code
• Critical pieces of code can be protected against
Control-C attacks and other such signals.
• It can be restored after the critical code has
executed.
38
Protecting Critical Code - Example
• Here’s the source code of a program that protects itself
against SIGINT signals:
$_
40
Sending Signals: kill()
• A process may send a signal to another process by using
the kill() system call.
• kill() is a misnomer, since many of the signals that it can
send to do not terminate a process.
• It’s called kill() because of historical reasons;
• the main use of signals when UNIX was first designed was
to terminate processes.
41
Sending Signals: kill()
• Syntax:
– int kill( pid_t pid, int sigCode )
42
Sending Signals: kill()
• There are a few variations on the way that kill()
works:
– If pid is zero, the signal is sent to all processes in the
sender’s process group.
– If the pid is negative, but not -1, the signal is sent to all
the processes in the process group. 43
Death of Children
• When a child terminates, the child process sends
its parent a SIGCHLD signal.
44
Death of Children - Example
• The program works by performing the following
steps:
1. The parent process installs a SIGCHLD handler that is
executed when its child process terminates.
47
Death of Children - Example
$ limit 5 ls ---> run the program; command finishes OK.
a.out alarm critical handler limit
alarm.c critical.c handler.c limit.c
Child 4030 terminated within 5 seconds.
$ limit 4 sleep 100 ---> run it again; command takes too long
Child 4032 exceeded limit and is being killed.
$-
48
Suspending and Resuming Processes
• The SIGSTOP and SIGCONT signals suspend and
resume a process, respectively.
49
Suspending and Resuming Processes
– Example
• The main program created two children that both
entered an infinite loop and displayed a message
every second.
50
Suspending and Resuming Processes
– Example
$ cat pulse.c ---> list the program.
#include <signal.h>
#include <stdio.h>
main()
{ int pid1;
int pid2;
pid1 = fork();
52
Suspending and Resuming Processes
– Example
$ pulse ---> run the program.
pid1 is alive ---> both run in first three seconds.
pid2 is alive
pid1 is alive
pid2 is alive
pid1 is alive
pid2 is alive
pid2 is alive ---> just the second child runs now.
pid2 is alive
pid2 is alive
pid1 is alive ---> the first child is resumed.
pid2 is alive
pid1 is alive
pid2 is alive
pid1 is alive
pid2 is alive
53