************* BACK AND FORTH PAGING SUBROUTINE ************

PAGEFLOP

If they want to quit, do so
 If They want to quit subsession, Do SO!
  Decrement LOCAL and GLOBAL Page Counters

FORWARD

  Increment LOCAL and GLOBAL Page Counters
   *************** END PAGEFLOP *********************
  ****** CHAPTER INTERNAL SELECTOR ALGORITHM ******

SELECTOR

   Reset Local Page Counter

SELAGAIN

 CHECK IF ONLY A <CR>

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().
??LATER: add for the advanced reader:  If a parent process is not
executing, the exiting child process turns into a zombie process
(an inactive process deleted at some later time)

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

???LATER chris says this is way too short !!! and offers suggestions:
  make a note that SIGKILL is only an example
  1st Give a table of signals, their numbers, and their meanings
  possibly in a separate subtopic
     Signal    Number    Meaning
     SIGHUP      1       hangup
  2nd: state the 3 possibilities
     SIGIGN
     SIG_DFL
     handler
  3rd: show the examples fro SIGKILL
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  */
}