Process Control: <stdlib.h>,<unistd.h>

A process is basically a single running program. It may be a "system" program (e.g login, update, csh) or program initiated by the user (textedit, dbxtool or a user written one).

When UNIX runs a process it gives each process a unique number - a process ID, pid.

The UNIX command ps will list all current processes running on your machine and will list the pid.

The C function int getpid() will return the pid of process that called this function.

A program usually runs as a single process. However later we will see how we can make programs run as several separate communicating processes.

Running UNIX Commands from C

We can run commands from a C program just as if they were from the UNIX command line by using the system() function. NOTE: this can save us a lot of time and hassle as we can run other (proven) programs, scripts etc. to do set tasks.

   int system(char *string) -- where string can be the name of a unix utility, an executable shell script or a user program. System returns the exit status of the shell. System is prototyped in <stdlib.h>

Example: Call ls from a program

{ printf("Files in Directory are:\n");
		 system("ls -l");

system is a call that is made up of 3 other system calls: execl(), wait() and fork() (which are prototyed in <unistd>)


execl has 5 other related functions -- see man pages.

execl stands for execute and leave which means that a process will get executed and then terminated by execl.

It is defined by:

execl(char *path, char *arg0,...,char *argn, 0);

The last parameter must always be 0. It is a NULL terminator. Since the argument list is variable we must have some way of telling C when it is to end. The NULL terminator does this job.

where path points to the name of a file holding a command that is to be executed, argo points to a string that is the same as path (or at least its last component.

arg1 ... argn are pointers to arguments for the command and 0 simply marks the end of the (variable) list of arguments.

So our above example could look like this also:

{ printf("Files in Directory are:\n");
		 execl("/bin/ls","ls", "-l",0);


int fork() turns a single process into 2 identical processes, known as the parent and the child. On success, fork() returns 0 to the child process and returns the process ID of the child process to the parent process. On failure, fork() returns -1 to the parent process, sets errno to indicate the error, and no child process is created.

NOTE: The child process will have its own unique PID.

The following program illustrates a simple use of fork, where two copies are made and run together (multitasking)

{ int return_value;
		 printf("Forking process\n");
		 printf("The process id is %d
		   and return value is %d\n",
		   getpid(), return_value);
		 printf("This line is not printed\n");

The Output of this would be:

Forking process
The process id is 6753 and return value is 0
The process id is 6754 and return value is 0
two lists of files in current directory

NOTE: The processes have unique ID's which will be different at each run.

It also impossible to tell in advance which process will get to CPU's time -- so one run may differ from the next.

When we spawn 2 processes we can easily detect (in each process) whether it is the child or parent since fork returns 0 to the child. We can trap any errors if fork returns a -1. i.e.:

int pid; /* process identifier */
pid = fork();
if ( pid < 0 )
		 { printf("Cannot fork!!\n");
if ( pid == 0 )
		 { /* Child process */ ...... } 
		 { /* Parent process pid is child's pid */
		 .... }


int wait (int *status_location) -- will force a parent process to wait for a child process to stop or terminate. wait() return the pid of the child or -1 for an error. The exit status of the child is returned to status_location.


void exit(int status) -- terminates the process which calls this function and returns the exit status value. Both UNIX and C (forked) programs can read the status value.

By convention, a status of 0 means normal termination any other value indicates an error or unusual occurrence. Many standard library calls have errors defined in the sys/stat.h header file. We can easily derive our own conventions.

A complete example of forking program is originally titled fork.c:

/* fork.c - example of a fork in a program */
/* The program asks for UNIX commands to be typed and inputted to a string*/
/* The string is then "parsed" by locating blanks etc. */
/* Each command and sorresponding arguments are put in a args array */
/* execvp is called to execute these commands in child process */
/* spawned by fork() */

/* cc -o fork fork.c */

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

    char buf[1024];
    char *args[64];

    for (;;) {
         * Prompt for and read a command.
        printf("Command: ");

        if (gets(buf) == NULL) {

         * Split the string into arguments.
        parse(buf, args);

         * Execute the command.

 * parse--split the command in buf into
 *         individual arguments.
parse(buf, args)
char *buf;
char **args;
    while (*buf != NULL) {
         * Strip whitespace.  Use nulls, so
         * that the previous argument is terminated
         * automatically.
        while ((*buf == ' ') || (*buf == '\t'))
            *buf++ = NULL;

         * Save the argument.
        *args++ = buf;

         * Skip over the argument.
        while ((*buf != NULL) && (*buf != ' ') && (*buf != '\t'))

    *args = NULL;

 * execute--spawn a child process and execute
 *           the program.
char **args;
    int pid, status;

     * Get a child process.
    if ((pid = fork()) < 0) {

	/* NOTE: perror() produces a short  error  message  on  the  standard
           error describing the last error encountered during a call to
           a system or library function.

     * The child executes the code inside the if.
    if (pid == 0) {
        execvp(*args, args);

       /* NOTE: The execv() vnd execvp versions of execl() are useful when the
          number  of  arguments is unknown in advance;
          The arguments to execv() and execvp()  are the name
          of the file to be executed and a vector of strings  contain-
          ing  the  arguments.   The last argument string must be fol-
          lowed by a 0 pointer. 

          execlp() and execvp() are called with the same arguments  as
          execl()  and  execv(),  but duplicate the shell's actions in
          searching for an executable file in a list  of  directories.
          The directory list is obtained from the environment.

     * The parent executes the wait.
    while (wait(&status) != pid)
        /* empty */ ;


Exercise 12727

Use popen() to pipe the rwho (UNIX command) output into more (UNIX command) in a C program.

Dave Marshall