PAGEFLOP
FORWARD
SELECTOR
SELAGAIN
WRONGSEL
YOUR SELECTION IS NOT IN THE 0 - #SELIMIT RANGE Please Try Again
AANVANG
Copyright CourseWare Technologies Inc., 1985-88
Lesson - 7
PROCESS CONTROL AND
SYSTEMS PROGRAMMING
MENU
Process Control|Topics to Learn|7-0|10,42
# Topic
--- -------
1 - Introduction to Process Control
2 - Process Control System Calls
3 - Process Control Examples
4 - Signal Processing Under UNIX
5 - Using the signal() Function
6 - A Complex Signal Example
7 - Lesson Review
0 - Return to the Main Menu
P1
Process Control|Introduction|7-1.1|14,54
Under UNIX, processes can be controlled equally
well from user-written programs or from the shell.
Under UNIX, process control is not a "sacred" task
and does not require a roomful of information manuals.
The ability to do process control from the program
level:
* eliminates the necessity for process supervision,
* eliminates the overhead of invoking another shell,
* enhances the capabilities of the UNIX system user.
P2
Process Control|Introduction|7-1.2|18,56
A program is an executable file. A process is an
instance of the program in execution. For many commands,
the Shell creates or forks a process know as a child
process, which executes the command. Exceptions to this
are the shell built-in commands like cd, exec, newgrp,
read, wait, and ulimit.
Every process has a process identification number (PID).
When a background or asynchronous process is started,
its PID is printed on the user's terminal:
$ tbl chapter_14 | nroff&
1276 ( PID for tbl )
1277 ( PID for nroff )
$ ( new prompt )
P3
Process Control|Introduction|7-1.3|17,60
Process control at the terminal level can be divided
into two parts:
1. Creation and management system calls (in Section 2 of
the programmers manual):
fork() - create a new (child) process
exec() - overlay the image of a program onto the
running process
wait() - wait for the exit of a previously forked process
exit() - finish the execution of a process
2. Signal handling system calls:
kill() - send a signal to a process which COULD be a
"kill" signal
signal() - specify the action upon receipt of a signal
P4
Process Control|System Calls|7-2.1|15,58
fork() creates a new process called a child process.
The process that invokes fork() is called the parent
process. A child process is a copy of the parent
process (they execute the same code) and inherits
almost all of the attributes of the parent process.
The main difference is the child and the parent have
different PID's.
fork() may fail when too many processes are running
on your system. If fork() is successful, that is, the
child and parent processes are running concurrently, they
each get a different return value from fork(). A 0 is
returned to the child process and the PID of the child
process is returned to the parent process.
P5
Process Control|System Calls|7-2.2|16,59
fork() is used to separate the child code from the parent
code. With the help of different return values, the parent
and the child can perform different tasks.
The following code illustrates how use fork() to program
the actions of the child and parent processes.
int pid;
if ((pid=fork()) = = 0) {
/* code for child process goes here
(typically an exit() call) */
}
/* code for parent process goes here */
(typically a wait() for the child process
to terminate) */
You will see some examples later.
P6
Process Control|System Calls|7-2.3|11,54
To actually execute the new process command,
the child process has to execute the execv()
system call, defined by:
int execv(path,argv);
char *path, *argv;
where path is the pointer to the pathname that
identifies the new process, and argv is an array
of pointers to the arguments of the new process,
if any.
P7
Process Control|System Calls|7-2.4|16,54
The parent process may "decide" to wait for the
child process to terminate or execute asynchronously.
The mechanism for process waiting is provided by the
system call wait() which is available in two forms:
int wait(status) int *status;
int wait ((int *) 0)
wait() suspends the calling process until one of the
child processes terminates. The return value of wait
is the PID of the terminating child process or -1 for
an error. In its first form, wait() puts status
information about the child process (the signal causing
termination or exit value of child) into the location
pointed to by status. In the second version, no status
information is provided.
P8
Process Control|System Calls|7-2.5|11,51
Finally, the system call exit() terminates
the present process. Its syntax is:
void exit(status)
int status;
where status is the exit status. An exit status of
0 usually indicates a successful exit.
Note: The parent process can get the child's
exit status by executing wait().
P9
Process Control|Process Control Examples|7-3.1|9,54
Let's consider an example. Assume that program
control controls 5 asynchronous processes. control
spans all five processes, that is, creates five
child processes and then waits for their termination.
If the exit status of a child process is not 0,
control will report the PID and the failure to the
user's terminal.
P10
Process Control|Process Control Examples|7-3.2|9,58
If all processes exit normally, control will report
this also. If all processes exited successfully, control
will exit with status of 0; otherwise, it will exit with
non-zero status.
NOTE: To avoid confusion when child processes, of
child processes terminate, it is best to have just one
parent process, with one or more children.
P11
Process Control|Process Control Examples|7-3.3|17,54
The control program:
#include <stdio.h>
char *processes[]={"proc1", "proc2", "proc3", "proc4",
"proc5"};
main()
{
int i, status;
int procid, exitstat=0;
for (i=0; i < 5; i++) {
if ((procid = fork()) == 0) { /* child */
if (execv(process[i], NULL) == -1)
exit(1);
break; /* if fork fails */
}
} continued on next screen ...
P12
Process Control|Process Control Examples|7-3.4|17,54
The control program continued:
/* wait for children */
if (procid != 0) { /* THEN THE PARENT PROCESS */
for (i=1; i <= 5; i++) {
procid = wait(&status);
if (status != 0) {
exitstat++;
printf("PROCESS %d FAILED\n", procid);
}
else
printf("PROCESS %d PASSED\n", procid);
}
}
exit(exitstat); /* EXIT CONTROL PROCESS */
}
P13
Process Control|Signal Processing|7-4.1|5,50
During execution, a process may encounter
various interrupts or signals, such as a hangup
from a terminal (SIGHUP), a terminal interrupt
(SIGINT), a quit signal (SIGQUIT), or a kill
signal (SIGKILL).
P14
Process Control|Signal Processing|7-4.2|10,54
A process has 3 ways of handling a signal:
1. Ignore the signal.
2. Transfer control to a specified function.
3. Let the system take a default action, which
is normally to terminate the process.
The SIGKILL signal cannot be caught or ignored.
It can be used to get rid of any of your processes.
P15
Process Control|Signal Processing|7-4.3|10,59
There are two functions that perform signal handling
under UNIX:
signal() - specifies what to do upon receipt of a signal
kill() - sends a signal to a process or a group of
processes. The superuser can send any signal
to any process; other users are limited to
processes with a matching user id. kill() is
often used by the command kill to send the
kill signal SIGKILL to the specified process.
P16
Process Control|Using the "signal()" Function|7-5.1|15,54
The signal() system call has two arguments:
1: the signal name (except SIGKILL) as defined in
the file signal.h which should be included as
<signal.h>, and 2: the action. signal() may be
used in the program as:
signal(SIGILL, SIG_IGN); if the signal for an
illegal instruction is to be ignored,
signal(SIGILL, SIG_DFL); if the default action
for an illegal instruction signal is to be taken,
signal(SIGILL, handler); if control should transfer
to the function "handler()" upon receiving an
illegal instruction signal.
P17
Process Control|A Complex Signal Example|7-6.1|8,54
A controlling process signaler spawns two
processes, then it disables the terminal interrupt
signals and waits for the return of the child
processes.
If the first child failed (returned error exit
status) then the second child is killed without
waiting for its completion.
P18
Process Control|A Complex Signal Example|7-6.2|18,54
A Signal Processing Example
#include <stdio.h>
#include <signal.h>
char *process[2] = {"proc1", "proc2"};
main()
{
int i, status, exitno;
int pid[2], exitstat=0;
for (i=0; i < 2; i++) {
if (( pid[i] = fork()) == 0) { /* child */
if( (execv(process[i], NULL) == -1)
exit(1);
break; /* If fork fails */
}
} program continued on next screen ...
P19
Process Control|A Complex Signal Example|7-6.3|18,54
/* WAIT FOR CHILDREN */
if (pid[1] != 0) { /* then the parent */
/* disable the interrupts */
signal(SIGINT, SIG_IGN); /* terminal interrupt */
signal(SIGQUIT, SIG_IGN); /* quit signal */
for (i=1; i <= 2; i++) {
exitno = wait(&status);
if (status != 0) { /* Kill the other */
if (exitno == pid[0])
i = 1;
else
i = 0;
kill(pid[i], SIGKILL);
exitstat++; break;
}
}
} exit(exitstat); /* exit control process */
}