Generic Process Operations

Contents

Introduction
Concurrent processes
Process Operations
Process creation
Standard C API

Introduction

Processes are the things that actually do the work.

Program

A program is a sequence of instructions. A program may be C source code. After compilation there is a program which is executable code. Neither of these actually do anything. Programs are stored on disk as static entities.

Process

A process is a dynamic invocation of a program along with the resources required to run. These include user and system stacks, memory, file handles, etc. Each process generally runs in a separate address space.

Concurrent processes

A process is usually sequential and consists of a sequence of actions that take place one at a time. When a set of processes are run on a single CPU, using timeslicing to multitask them, this is referred to as concurrent sequential processing or pseudo-parallel processing. If there is more than one CPU available, then processes may be run in parallel.

Process Operations

The set of operations on processes includes The O/S will supply mechanisms for at least some of these.

Process creation

There must be a mechanism for creating processes by the O/S. A new process will be created using an existing one. There are several possible organisations of this.

Synchronous

If a process is created from another as a synchronous process then the new must complete execution before the old one can resume.

Asynchronous

If the new process is created asynchronously, then the two processes may be run in pseudo-parallel.

Parent

When a new process is created, it may use the old one as ``parent''. This is done in MSDOS and Unix. Alternatively, there may be no relation between the original and the new process, as in Windows NT.

Granularity

Processes vary in the amount of complexity required to set them up and the amount of sharing with the parent.

Standard C API

The standard C library has a call
#include 
int system(char *command)
This creates a new synchronous process. It does so by passing the command to the command processor (eg bash) which executes in the current command processor environment. When the process completes the system call finishes and the calling process can continue.

Example:

Read lines from standard input and execute them as commands.
#include <stdio.h>

int main(void)
{  char command[1024];

   printf("Enter commands, one per line:\n");
   while (gets(command) != NULL)
      system(command);
   exit(0);
}


The called process may in turn make a call to ``system''. This allows a stack of processes to be built, each of which is suspended when a new process is placed on the stack, and can resume when it becomes the top-of-stack process again. This mechanism is available in both MSDOS and Unix.

Unix Process API

Contents

Process creation
fork
exec
Example:
Process suspension
Process removal
Process environment
Information sharing
X Windows and Processes

Process creation

The Unix API allows creation of asynchronous processes where each process has a parent. Each process has a process ID (a number) that can be used to tell them apart. This PID is shown in the user-level command ``ps''. Because the parent process can resume execution before a child terminates, the parent can continue to create processes. The children can also create processes
fork
This creates a tree of processes.
tree
or
tree

fork

The function call to do this is
#include <sys/types.h>
pid_t fork(void)
This splits the current process into two almost identical copies. A copy is made of the user and system stacks, of the allocated data space and of the registers. The major difference is that one has the PID of the parent, the other has a new PID. The fork returns a value that is a PID. The PID is zero if you are the child, or the PID of the child if you are the parent.
Example: This creates one child:
#include <stdio.h>
#include <sys/types.h>

int main(void)
{ pid_t pid;

  pid = fork();
  if (pid == -1) {
    fprintf(stderr, 
           "fork failed\n");
    exit(1);
  }
  if (pid == 0) {
    printf("I'm the child\n");
    exit(0);
  }
  if (pid > 0) {
    printf("I'm the parent \
with child %d\n", pid);
    exit(0);
  }
}


What order are these two messages printed in? The child and the parent can call any functions in the program, and execute as independent processes with the same program code. There is (at present) no communication between them.

exec

It is common to want to replace one of these processes so that it uses a different program. For example, suppose the process creates a file that it wants printed. In Unix it cannot print it itself, because it does not have access to the line printer device. The program ``lpr'' must be used. One way is
system("lpr myfile");
This runs synchronously, so until the line printer program terminates the calling program suspends. Printing an empty file takes about 150 milliseconds. A preferable way may be to fork a new process and let the parent continue with the main piece of work, while the child prints the file asynchronously. This is possible, but cruddy:
if (fork() == 0)
  system("lpr myfile");
else { /* parent */ }
It creates a child process that does nothing but wait for ``system'' to finish. Better is to replace the child with the ``lpr'' program. This is the job of the ``exec'' functions
int execlp(char *file,
           char *arg0,
           char *arg1,
           ....
           char *argn,
           (char *) 0);
The ``file'' argument is the name of the program to execute. This uses the PATH environment variable to find the file (like shell commands do). ``arg0'' is often the same as ``file''. This is used as the name of the process, as reported by ``ps''. ``arg1'' to ``argn'' are the arguments to the command. This must be terminated by a NULL pointer to show the end of the list. In normal operation ``exec'' never returns. If if fails, it returns -1.

Example:

Fork and use exec to print a file
if (fork() == 0)
  if (execlp("lpr",
             "lpr",
             "myfile", 
             (char *) 0) == -1)
    fprintf(stderr,
            "exec failed\n");
else { /* parent */ }
or more simply
if (fork() == 0)
{
  execlp("lpr",
         "lpr",
         "myfile", 
         (char *) 0);
  fprintf(stderr,
          "exec failed\n");
}
else { /* parent */ }
Here is a simple example:
#include <;stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <sys/types.h>

int main(int argc, char *argv[])
{
  pid_t pid;

  if ((pid = fork()) < 0)
  {
    fprintf(stderr,
	    "fork failed\n");
    exit(1);
  }

  if (pid == 0)
  {
    execlp("echo",
	   "echo",
	   "Hello from",
	   "the child",
	   (char *) NULL);
    fprintf(stderr, 
    	   "execl failed\n");
    exit(2);
  }

  printf("parent carries on\n");
  exit(0);
}


(What happens if the exit(2) is removed and the execlp fails? Why?)

Process suspension

wait

Suppose the file was a temporary file. After printing, it should be deleted. The child cannot delete it, because after the ``exec'' it no longer exists. The parent cannot directly delete it because the ``lpr'' program may still be accessing it. (Actually, an option on lpr allows removal after printing - ignore this.) When ``lpr'' terminates, the parent can remove the file. So the parent has to be able to decide when a child has finished.
#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *status)
This waits for a process to terminate and returns the PID of one that did. It also returns status information.
if ((pid = fork()) == 0)
  if (execlp("lpr",
             "lpr",
             "myfile", 
             (char *) 0) == -1)
    fprintf(stderr,
            "exec failed\n");
else {
  /* do lots of things while
     the printing takes place
   */

  /* now remove the file */
  while (wait(NULL) != pid)
    ;
  unlink("myfile");

  /* and do lots more things */
}

sleep

A process may suspend for a period of time using the sleep command
unsigned int sleep(seconds)
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <sys/types.h>

int main(int argc, char *argv[])
{
  pid_t pid;

  if ((pid = fork()) == 0)
  { /* child */
    printf("sleeping...\n");
    sleep(5);
    printf("waking ... and exiting\n");
  } else {
    if (pid > 0)
    {
      printf("waiting for child\n");
      wait(NULL);
      printf("child woke up\n");
    }
  }
}


Process removal

exit

When a process executes the ``exit'' command it terminates.

kill

One process can send simple messages to another using the ``kill'' command
#include <sys/types.h>
#include <signal.h>
int kill( pid_t pid, int sig);
The process to which the signal is sent must have the same uid or be a ``super user'' process. The signal is often SIGINT or SIGKILL.
if (pid = (fork() == 0))
  ...
else {
  /* let the child run for
     10 seconds max
   */
  sleep(10);
  kill(pid, SIGINT);
}

signal

A process can catch certain signals by installing a signal handler which is a function invoked when the signal arrives.
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/types.h>

void int_handler(int sig)
{
  printf("Ouch - shot in the ...\n");
  exit(2);
}

int main(int argc, char *argv[])
{
  pid_t pid;

  if ((pid = fork()) < 0)
  {
    fprintf(stderr,
	    "fork failed\n");
    exit(1);
  }

  if (pid == 0)
  {
    signal(SIGINT, int_handler);
    while (1)
      printf("Running amok!!!\n");
  }

  sleep(3);
  kill(pid, SIGINT);
  exit(0);
}


Process environment

A process has an entry in a table of processes. This table contains all sorts of information (see ``internals'' lecture) including user ID, current directory, etc. A set of function calls allows access to much of this information:

Process ID

#include <:sys/types.h>
pid_t getpid(void);

User ID

#include 
uid_t getuid(void);

User name

char *getlogin(void);

Current directory

char *getcwd(char *dir,
             int size);
Example: Who is running this program?
#include <stdio.h>

int main(void)
{ char *login;

  if ((login = getlogin())
          != NULL)
    puts(login);
}


Information sharing

When a new process is created from a parent, some information is new, some is copied and some id shared: Other facets of process information follow this:

X Windows and Processes

Process state does not include any information about X Windows - X is treated just like any other application. Creating an X process is no different to other applications. However, there are these cases:
Home Systems Software Home
Jan Newmarch (http://jan.newmarch.name) <jan@newmarch.name>

Copyright © Jan Newmarch
Last modified: Mon Feb 17 22:37:55 EST 2003