Interprocess Communication

Look at Unix primitives. Also covered in Tanenbaum chapter on Unix.

How does one process communicate with another process?

Software Interrupts

Similar to hardware interrupt; processes interrupt each other through software operations. Important to realize that interrupts are asynchronous! Stops execution and then restarts.

Examples:

/* example in /cs/cs3013/public/example/signal.c */

#include <signal.h>

int n;

main(int argc, char **argv)
{
    void InterruptHandler(), InitHandler();

    n = 0;

    signal(SIGINT, InterruptHandler); /* signal 2 */
    signal(SIGHUP, InitHandler);      /* signal 1 */
    while (1) {
        n++;
        sleep(1);
    }
}

void InterruptHandler()
{
    printf("The current value of n is %d\n", n);
    exit(0);
}

void InitHandler()
{
    printf("Resetting the value of n to zero\n");
    n = 0;
}

% cc -o signal signal.c
% ./signal
./signal
^C           (interrupt character)
The current value of n is 3
% ./signal &
[1] 20822
% kill -1 %1
Resetting the value of n to zero
% kill -2 %1
The current value of n is 19
[1]    Done                 ./signal

Pipes

In Unix, a pipe is a unidirectional, stream communication abstraction. Show a picture!! One process writes to the ``write end'' of the pipe, and a second process reads from the ``read end'' of the pipe.

The command interpreter is responsible for setting up a pipe. For instance, upon entering:

% ls | more
the shell would:
1.
create a pipe.
2.
create a process for the ls command, setting stdout to the write side of the pipe.
3.
create a process for the more program, setting stdin to the read side of the pipe.

A pipe consists of (keep using the same picture showing the pipe as a buffer)

Pipes unify input and output. When a process starts up, it inherits open file descriptors from its parent.

Thus, when a process reads from standard input, it doesn't know (or care!) whether it is reading from a file or from another process.

Likewise, output written to standard output might go to a terminal, a file, or another process.

System calls:

/* /cs/cs3013/public/example/pipe.c */

#define DATA "hello world"
#define BUFFSIZE 1024

int rgfd[2];    /* file descriptors of streams */

/* NO ERROR CHECKING, ILLUSTRATION ONLY!!!!! */

main()
{
    char sbBuf[BUFFSIZE];

    pipe(rgfd);    
    if (fork()) { /* parent, read from pipe */
        close(rgfd[1]);   /* close write end */
        read(rgfd[0], sbBuf, BUFFSIZE);
        printf("-->%s\n", sbBuf);
        close(rgfd[0]);
    }
    else { /* child, write data to pipe */
        close(rgfd[0]);   /* close read end */
        write(rgfd[1], DATA, sizeof(DATA));
        close(rgfd[1]);
        exit(0);
    }
}

For the following, which is the parent and which is the child? (parent should read from pipe so ``more'' is the parent process). Last to complete.

% ls | more

Look at example 1-14. Tanenbaum uses dup(oldd) to duplicate a file descriptor. Also have a dup2(oldd, newd), which explicitly gives the new file descriptor.