.	C manual - Process control -nroff with cdoc0
.HI 3
.ce
C Manual - Process Control
.ce
Edited by R.P.A. Collinson
.ce
Document No: DOC/UNIX.K3.10/3
.sp 5
.ce
Contents
.in+20
.SC 1 Introduction
.SC 2 "Manual Pages"
.br
exec, exit, fork, kill, pipe, signal, sleep, wait
.in-20
.sp 10
.so unixlicense
.SH 1 Introduction
.NF
.PG
This manual gives details for C programmers on the various aspects of 
controlling processes under Unix.  The manual requires a basic knowledge
of the Unix operation system, the C language and I/O in C.  There are three
UKC documents which are relevant:
.sp
1)	DOC/UNIX.K0/1: Unix Introduction.
.br
2)	DOC/UNIX.K3.10/1: C Manual - Language.
.br
3)	DOC/UNIX.K3.10/2: C Manual - Input/Output.
.PG
The second section of this manual contains reprints of relevant
manual pages from the "Unix Programmers Manual" from Bell Labs., but
because these pages are not good introductory explanations,
an explanation of the use of the various system primitives will be attempted here.
.SB Signals
.PG
Signals are fundamental to process control in Unix, a signal is the only method
by which a process can control another. A signal can be considered as an interrupt
which is sent to a process to cause it to either stop or to initiate some other action.
Normally, signals are not trapped by the process and on receipt of the signal the
process stops executing (some signals will cause a core dump to a file called 'core'
before killing the process).
.PG
The action of the most common signal (Interrupt - which is Control G on UKC Unix)
in the default case is as follows.
When the interrupt key is hit during the running of a program, the teletype
driver sends the 'interrupt' signal to the appropriate process(es).
All the system does is to set a bit in the process control data area for the
process(es) saying that the signal has occured.  When the system next attempts to swop
the process
in (or out), it looks to see whether a signal has occured and if so takes the appropriate
action. So, in the default case, the process to which the signal has been sent is
interrupted and stopped.
.PG
The
.it kill
(I) command and the 
.it kill
(II) system call are really misnamed, all they do is send a signal to the named
process, which in turn acts on it.  So a background process (say 1765) may be
interrupted by saying
.sp
	kill -2 1765
.sp
(2 is the internal number for the interrupt signal). Notice that
.sp
	kill 1765
.sp
is the same as
.sp
	kill -9 1765
.PG
In a C program, the routine
.it signal
(II) is used to trap signals and causes the process to execute
a specific routine when a specified signal is received. For example, if a
program had a temporary file which was to be deleted before exit from the
program was effected, the code would look like:
.sp
	char tfile[] "/tmp/tfile";	/* Temp file name */
	.
	.
	.
	main()
	{	int leave();	/* Tell the compiler 'leave'
				 * is a routine */
		.
		.
		.
		.
		signal(2, &leave);
		.
		.
		.
	}

	leave()
	{	unlink(tfile);
		exit();
	}

When the interrupt key was hit, the routine 'leave' would be entered; this
would delete the file and exit from the process.
.PG
It is quite legal to continue execution of the program when the
signal trap routine has been executed, execution will continue (as if there had
been an interrupt) at the instruction after the one which was being executed
when the 'interrupt' occured.
However, there is a complication here. If the program was performing a system call at the
time the interrupt key was hit (and this is common with I/O bound programs), the system
call code is aborted and the system call will return an error value (= 4 - see System Error
Values in Section II of the Unix programmers Manual). On receipt of this
error message, the system call should be re-executed as if it had not been started
in the first place and will operate correctly.  The main problem is that getc and getchar
do not trap this message and pass it back to the user as an end of file mark, which is
often used to cause an exit from the program.
There are a lot of ways round this problem but
no space to go into them here.
.PG
It is often common for an interrupt to be used to alter the flow of control
of a program.
For instance:
.sp

	.
	.
	main()
	{	int leave();
		.
		.
		.
		setexit();	/* See reset(III) */
		signa(2, leave);
		for(;;)
		{	.
			.
			.
			processing in a loop
			.
			.
		}
	}

	leave()
	{	reset();	}

In this case, setexit stores the stack pointers and program counter at the top level in the
main routine and the interrupt routine will reset the stack and program counter to the correct
value. Notice that the call to signal is placed after the call to setexit so that the
signal is re-trapped, because a particular signal (sensibly) turns off the trapping for
the signal.  If the 'leave' routine has to perform a lengthy operation (basically
anything concerned with I/O or file handling) it is good practice to write it as:
.sp
	leave()
	{	signal(2, 0);		/* Ignore interrupts */
		.
		.
		.
		.
		reset();
	}

Otherwise, two Control-G's typed in quick succession will 'interrupt' the leave routine,
leaving lots of mess behind and possibly causing an unwanted exit from the program.
.SB "Fork and Exit"
.PG
.it Fork
(II) is the system call used to create child processes. Its action is to create another
process which is an exact duplicate (clone?) of the parent process. There is one
difference between the two processes immediately after the creation, the value
returned by 
.it fork
in the child is zero and the value returned to the parent is a positive number
giving the process id of the child.
.it Fork
will return a negative number if it cannot create a new process, it is good
practice to test for this value and exit if a new process cannot be created.
.PG
.it Wait
(II)
is used to synchronise the activity of processes, it causes the parent process to wait until
one of its children terminates. A program which uses fork should never exit unless a wait
call has been issued, the program should never leave any of its children lying about the system.
.PG
.it Exec
(II) comes in two versions and is often used in conjunction with
.it fork
but this need not always be the case. Its action is to completely overlay the process it is called
from with a new program.  The new program is then set to a run state starting at the beginning. So, it changes
the identity of a process. Note that by convention argument
0 to a program is always its name, so to execute
the copy program the C statement would read
.sp
	execl("/bin/cp", "cp", "source", "dest", 0);
.sp
This statement will cause the current process to be overwritten with the code
and data segments from the file '/bin/cp', and the new program is started with the
arguments: 'cp' - the name of the process; and two files 'source' and 'dest'.
.PG
The three system calls may be used in a variety of ways, a common method is given in the following
example. If a program was required to copy a file, this could be coded as follows:
.sp

	/* Copy a file named by string s to file named by string d */
	filecopy(s, d)
	char *s, *d;
	{	int pid;
		if((pid = fork()) < 0)
		{	printf("Cannot create new processes\\n");
			exit();
		}
		if(pid)
			wait();	/* All the parent does is
				 * wait for the child */
		else
		{	/* Code for child */
			execl("/bin/cp", "cp", s, d, 0);
			/* there is no return from the exec call
			 * unless /bin/cp cannot be found - you could
			 * insert the following code just to make sure
			 */
			printf("Cannot find /bin/cp\\n");
			exit();
		}
	}

.SB "Example program"
.PG
The following example program illustrates all the features mentioned above.  It also uses pipes which act
in exactly the same manner as standard I/O streams except:
.br
1)	It is not possible to 'seek' on them.
.br
2)	An end of file is not sent down a pipe unless
.it all
the file descriptors refering to its write end are closed in all processes.  If this
is not done, a child process which tests for end of file on input will wait for ever.
.PG
The program below is a complete 'utility' program and is a subset of the 'list'
command present on the UKC system.  For the sake of brevity, it will be called 'list'.  The
basic aim of the program is to take a file and print it on the standard output with line
numbers. The system utility 'lineno' takes its standard input and passes it to the standard
output adding line numbers. The utility 'pr' is then used to print the file with
pagination and page headings. 'Lineno' and 'pr' are set up as parallel processes communicating
via a pipe, the process 'list' remains as a controlling process.
.PG
The program will be called by the command
.sp
	list filename
.sp
but it may also be used as a filter, e.g. it could be called
by
.sp
	cat filename|list
.sp
.nf
/*
 *	Example 'list' program
 *	Called by
 *	list filename
 *	or can be used as a filter
 */


/* Global definition */

int proccount;		/* Count of active child processes 
			 * used for testing for necessity of killing 
			 * them on interrupt */

main(argc, argv)
int argc; char **argv;
{
	int brkroutine();	/* Tell the compiler that brkroutine
				 * is a routine */
	/* Trap interrupts from keyboard */
	signal(2, &brkroutine);

	/* Test for too many arguments */
	if(argc > 2)
	{	printf("Too many arguments\\n");
		exit();
	}

	/* Do we have a filename parameter */
	if(argc != 1)
		/* Yes we do -  pass it to listfile */
		listfile(argv[1]);
	else
	/* Call listfile with 0 - to indicate that program is a filter */
	listfile(0);
}

/* listfile routine - actually does all the work */

listfile(file)
char *file;
{
	int pv[2];	/* used to store pipe file descriptors (fds) */

	if(file)
	{	/* If there is an input file open it
		 * making sure that it is opened as channel 0 (the
		 * standard input - so that there is no messing about
		 * if the program is being used as a filter */

		close(0);	/* this ensures the next open file will
				 * have fd = 0 */
		if(open(file, 0) < 0)
		{	/* Tough - can't open file */
			printf("Cannot open: %s\\n", file);
			exit();
		}
	}

	/* At this point we know that
	 * Input is to come from channel 0
	 * Output from pr is to go to channel 1
	 */

	/* create the pipe channels */

	pipe(pv);

	/* fork for the process that will become lineno */

	if(newproc() == 0)
	{	/* Child code that will become lineno
		 * but first we must re-arrange its standard output
		 * to be the pipe */

		close(1);	/* Remember this only happens in child */
		dup(pv[1]);	/* Yes - this is what dup is for
				 * we now have two fds refering to pipe
				 * we must close the output half */
		close(pv[1]);
		/* perform the execl - 
		 * Channel 0 is the input file (or filter)
		 * Channel 1 is the output half of the pipe
		 */

		execl("/bin/lineno", "lineno", 0);
	}	/* End of child code */

	/* We now must make sure that the output half of the pipe
	 * is closed so that 'pr' will get an EOF when lineno finishes 
	 */
	close(pv[1]);

	/* Fork again for pr */

	if(newproc() == 0)
	{	/* Child that will be pr
		 * channel 0 should be read half of pipe
		 * channel 1 is already the standard output of parent
		 */

		close(0);
		dup(pv[0]);
		close(pv[0]);
		execl("/bin/pr", "pr", "-h", file, 0);
	}

	/* The parent must do what all good parents do
	 * wait for the children to finish
	 * wait will return -1 if there are no children left alive
	 * so keep waiting until this happens
	 */

	while(wait() >= 0);
}

/*
 * Newproc performs the fork and
 * tests for no processes being created
 * it also maintains a count of currently
 * alive children so that brkroutine can tidy the
 * system up after a interrupt key hit
 */

int newproc()
{	register int pid;

	if((pid = fork()) < 0)
	{	printf("Cannot create new processes/n");
		/* Could just exit here but want to ensure that
		 * there are no 'live' processes lying about so
		 * call brkroutine to do this
		*/

		brkroutine();
	}
	proccount++;		/* Increment live process count */
	return(pid);
}

/*
 * brkroutine - kills all child processes and exits
 */

brkroutine()
{	if(proccount)
	{	kill(0, 2);	/* send interrupt signal to children */
		while(wait()>=0);	/* Wait until they are dead */
	}
	exit();
}
.fi
.SH 2 "Manual pages"
.PG
This section contains the relevant manual pages for the system calls
mentioned in Section 1.
The calls are:
.sp
.in+20
.ti-20
exec	execute a named file.
.ti-20
exit	exit from a process.
.ti-20
fork	create a new process.
.ti-20
kill	send a signal to a process.
.ti-20
pipe	set up a pipe for interprocess communication.
.ti-20
signal	trap signals in a process.
.ti-20
sleep	suspend execution for an interval.
.ti-20
wait	wait for child processes to terminate.
.in-20
