\documentclass{ictlab}

\RCS $Revision: 1.2 $

\usepackage{alltt,key,color,answer2,float,afterpage,xr,biganswerbox}
%\externaldocument[proc-]{../../lectures/processes/processes-print-3}
\usepackage[nolineno,noindent]{lgrind}
%\usepackage[leftnum,lineno5,noindent]{lgrind}

\ifx\pdftexversion\undefined \else
  \usepackage[pdfpagemode=None,pdfauthor={Nick Urbanik}]{hyperref}
\fi

\renewcommand*{\subject}{Operating Systems and Systems Integration}

\newcommand*{\labTitle}{Workshop on Inter Process Communication}


\definecolor{light-blue}{rgb}{0.4,0.4,1}
\newcommand*{\gl}[1]{\textcolor{light-blue}{#1}} % good link
\newcommand*{\ex}[1]{\textcolor{green}{#1}} % executable file
\newcommand*{\bl}[1]{\colorbox{red}{\textcolor{white}{\textbf{#1}}}} % bad link

\renewcommand{\floatpagefraction}{0.75} % default is .5, to increase
% density.
\renewcommand*{\bottomfraction}{0.6} % default is 0.3
\renewcommand*{\topfraction}{0.85} % default is 0.7
\renewcommand*{\textfraction}{0.1} % default is 0.2

\setlength{\extrarowheight}{1pt}
\floatstyle{ruled}
\floatname{program}{Program}
\newfloat{program}{tbh}{lop}

\providecommand*{\IPC}{\acro{IPC}\xspace}

\begin{Solutions}
  \gdef\solution{\item[\textbf{Solution:}]}
\end{Solutions}

\begin{document}

\section{Background}
\label{sec:background}

Threads can share information with each other quite easily (if they
belong to the same process), since they share the same memory space.
But processes have totally isolated memory spaces, and cannot talk to
each other easily.  However, often we need processes to send
information to each other, so the need for Inter Process
Communication, or \IPC.

We examine a few methods for processes to talk with each other, and
try out some of the simpler ones.


\section{System Calls}
\label{sec:system-calls}

We use a number of system calls today.  Each one has its own manual
page in \emph{section 2}.  For example, to read about the
\texttt{fork()} system call, see \texttt{man 2 fork}.  Here are some
function prototypes for each system call that we use, copied from the
manual pages.

\subsection{System Calls for Pipes}
\label{sec:system-calls-for-pipes}

The \texttt{pipe()} system call sets up a one-way communication
channel between two processes.  The parameter is an array of two file
descriptors.  \texttt{filedes[0]} is for reading, \texttt{filedes[1]}
is for writing.  These are file descriptors; you have used file
descriptors 0, 1 and 2 for standard input, standard output and
standard error already.  Every open file has a file descriptor,
including a pipe.  You write to the second file descriptor and read
from the first one.  See figure~\vref{fig:pipe-file-descriptors}.
\begin{alltt}
#include <unistd.h>
int pipe(int filedes[2]);
\end{alltt}

\subsection{System Calls for Signals}
\label{sec:system-calls-for-signals}


\texttt{signal()} installs a new signal handler for the signal with
number signum.  The signal handler is set to sighandler which may be a
user specified function, or either \texttt{SIG\_IGN} or
\texttt{SIG\_DFL}.

Using a signal handler function for a signal is called "catching the
signal".  The signals \texttt{SIGKILL} and \texttt{SIGSTOP} cannot be
caught or ignored.

You can see a complete list of signals if you type \texttt{kill~-l}.
\begin{alltt}
#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
\end{alltt}

\subsection{Error Handling of System Calls}
\label{sec:error-handling}

Note that all the system calls used here return the value $-1$ when
there is an error, and set a global variable called \texttt{errno} to
an error number.  There is a library function called \texttt{perror()}
which can print an error message when \texttt{errno} is set.  See
\texttt{man 3 perror} for more information, and see the example
\texttt{signal.c} in program~\vref{prg:signal-example}.
\begin{figure}[htb]
  \centering%
  \includegraphics[width=0.6\linewidth]{pipe-file-descriptors}
  \caption{How to read and write a pipe: read from the first,
    write to the second file descriptor.}
  \label{fig:pipe-file-descriptors}
\end{figure}
    
\section{Interprocess Communication (IPC)}
\IPC Techniques include:
\begin{itemize*}
\item pipes, and named pipes (\FIFO{}s)
\item sockets
\item messages and message queues
\item shared memory regions
\item signals
\end{itemize*}
All have some overhead

\subsection{Pipes and Named Pipes}
\begin{itemize*}
\item Circular buffer, can be written by one process, read by another
  \begin{itemize*}
  \item related processes can use \emph{unnamed pipes}
    \begin{itemize*}
    \item Trivial in shell programming: \texttt{ls \textbar{} grep
        rpm}
    \item Quite easy in C; see program~\vref{prg:pipe-example}.  The
      \texttt{pipe()} system call takes an array of two integers.
      
    \item A limitation of unnamed pipes is that the two processes must
      be related (have a common ancestor) --- usually, between a
      parent and child process.
      \begin{program}[tbh]
        \vspace*{-2ex}
%[
#include <stdio.h>
#include <sys/wait.h>
#include <unistd.h>
#define BUFSIZE 30
int main() {
        int pipe_file_descriptors[2];
        char buf[BUFSIZE];

        pipe( pipe_file_descriptors );
        
        if ( fork() == 0 ) {
                printf( " CHILD: reading from pipe\n" );
                read( pipe_file_descriptors[0], buf, BUFSIZE );
                printf( " CHILD: read \"%s\"\n", buf );
        } else {
                printf( "PARENT: writing to the pipe\n" );
                write( pipe_file_descriptors[1], "test", BUFSIZE );
                printf( "PARENT: finished writing\n" );
                wait( NULL );
        }
        return 0;
}
%]
        \vspace*{-3ex}
        \caption{A Pipe---simplest \IPC.  The \texttt{pipe()} system
          call takes an array of two file descriptors; one process
          reads from the first, the other process writes to the
          second.}
        \label{prg:pipe-example}
      \end{program}

      
    \end{itemize*}
  \item unrelated processes can use \emph{named pipes} ---
    sometimes called \FIFO{}s
  \end{itemize*}
\item Limitation: \emph{one direction} only
\end{itemize*}

\subsection{Sockets}
\begin{itemize*}
\item Very similar to network progamming with sockets, but on the same
  machine
\item A little more complicated than pipes, but can send data \emph{both
  ways}
\end{itemize*}

\subsection{Messages}
  \begin{itemize*}
  \item \emph{Messages} --- \POSIX provides system calls
    \texttt{msgsnd()} and \texttt{msgrcv()}
    \begin{itemize*}
    \item message is block of text with a type
    \item each process has a message queue, like a mailbox
    \item processes are suspended when attempt to read from empty
      queue, or write to full queue.
    \end{itemize*}
  \end{itemize*}

\subsection{IPC --- Shared Memory}
\begin{itemize*}
\item \emph{Shared Memory} --- a Common block of memory shared
  by many processes
\item Fastest way of communicating
\item Requires synchronisation
\end{itemize*}

\subsection{IPC --- Signals}
\begin{itemize*}
\item Some \emph{signals} can be generated from the keyboard,
  i.e., \key{Control-C} --- interrupt (\texttt{SIGINT});
  \key{Control-\bs} --- quit (\texttt{SIGQUIT}), \key{Control-Z} ---
  stop (\texttt{SIGSTOP})
\item A software \emph{signal} that sends an asynchronous number
  to a process
\item implemented as single bits in a field in the processs table, so
  cannot be queued
\item A process may respond to a signal with:
  \begin{itemize*}
  \item a default action (i.e., terminate)
  \item a signal handler function (see \texttt{trap} in shell
    programming notes), or
  \item ignore the signal (unless it is \texttt{SIGKILL} or
    \texttt{SIGSTOP})
  \item In shell programming, we used \texttt{trap} to change response
    to a signal, as in program~\vref{prg:signal-shell-example}.
    \begin{program}[tbh]
\begin{verbatim}
#! /bin/sh
trap "echo 'Got an Interrupt!'" INT
echo Enter a string:
read string
echo You entered: $string
\end{verbatim}%$
      \caption{A shell script  \texttt{signal.sh} that catches the
        interrupt signal (\texttt{SIGINT}), like the C
        program~\vref{prg:signal-example}.}
      \label{prg:signal-shell-example}
    \end{program}
  \item \POSIX introduces many functions to handle sets of signals,
    but the old \ANSI C interface is quite simple---see
    program~\vref{prg:signal-example}
  \end{itemize*}
\end{itemize*}

\begin{program}[tbh]
\vspace*{-2ex}
%[
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <signal.h>
#define MAX_LEN 200

void sigint_handler( int sig ) {
        printf( "Got an Interrupt!\n" );
}

int main( void ) {
        char s[MAX_LEN];

        if ( signal( SIGINT, sigint_handler ) == SIG_ERR ) {
                perror( "signal" );
                exit( 1 );
        }

        printf( "Enter a string:\n" );

        if ( fgets( s, MAX_LEN, stdin ) == NULL )
                perror( "fgets" );
        else 
                printf( "You entered: %s", s );

        return 0;
}
%]
\vspace*{-3ex}
\caption{A program \texttt{signal.c} that catches the Interrupt signal
  (\texttt{SIGINT}), slightly modified from \cite{bib:Beej97}.}
\label{prg:signal-example}
  \end{program}

\section{Procedure}
\label{sec:procedure}



%% \begin{program}[tbh]
%%     %\smallskip%
%% %\begin{verbatim}
%% \vspace*{-2ex}
%% %[
%% %]
%% \vspace*{-3ex}
%% %\end{verbatim}
%% \caption{Named Pipe.}
%% \label{prg:deadlock1}
%% \end{program}

\begin{enumerate}
\item Take the program \texttt{pipe.c} in
  program~\vref{prg:pipe-example}, compile and execute it.
\item Write a list of all the ``things that can go wrong'' in
  \texttt{pipe.c}:
  \begin{biganswerbox}[0.8cm]
    \begin{solution}%
      \texttt{pipe()}, \texttt{fork()}, \texttt{read()},
      \texttt{write()}, \texttt{printf()}, \texttt{wait()}.
    \end{solution}
  \end{biganswerbox}
\item Modify it to add error handling using \texttt{perror()}.  See
  section~\vref{sec:error-handling}.
  \begin{solution}
Here is one possible solution:
%[
#include <stdio.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#define BUFSIZE 30
int main() {
        int pipe_file_descriptors[2];
        char buf[BUFSIZE];
        int count, rv;
        pid_t pid;

        if ( pipe( pipe_file_descriptors ) == -1 ) {
                perror( "pipe" ); exit( 1 );
        }
        
        if ( ( pid = fork() ) == -1 ) {
                perror( "fork" ); exit( 1 );
        } else if ( pid == 0 ) {
                printf( " CHILD: reading from pipe\n" );
                count = read( pipe_file_descriptors[0], buf, BUFSIZE );
                if ( count == -1 ) {
                        perror( "read" ); exit( 1 );
                }
                printf( " CHILD: read %d bytes: \"%s\"\n", count, buf );
        } else {
                printf( "PARENT: writing to the pipe\n" );
                count = write( pipe_file_descriptors[1], "test", BUFSIZE );
                if ( count == -1 ) {
                        perror( "write" ); exit( 1 );
                }
                rv = printf( "PARENT: finished writing %d bytes\n", count );
                if ( rv < 0 ) { perror( "printf" ); exit( 1 ); }
                wait( NULL );
        }
        return 0;
}
%]
  \end{solution}
\item Modify \texttt{pipe.c} to send a large block of data (say a
  megabyte), and time how long it takes using the shell built-in
  function \texttt{time}.  You can use it like this:
\begin{alltt}
$ \textbf{time ./pipe2}
\end{alltt}%$
where \texttt{pipe2} is the executable of your modified
\texttt{pipe.c}.

I suggest that you initialise the buffer in the parent (writing)
process using a \texttt{for} loop, then send that copy of the buffer
to the other (child) process.   Add a null character
\texttt{'\bs0'} at the end of your buffer before the parent prints it
with \texttt{printf()}.

  \begin{solution}
Here is one possible solution:
%[
#include <stdio.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#define BUFSIZE ( 5 * 1024 * 1024 )
int main() {
        int pipe_file_descriptors[2];
        char buf[BUFSIZE];
        pid_t pid;

        if ( pipe( pipe_file_descriptors ) == -1 ) {
                perror( "pipe" ); exit( 1 );
        }
        
        if ( ( pid = fork() ) == -1 ) {
                perror( "fork" ); exit( 1 );
        } else if ( pid == 0 ) {
                printf( " CHILD: reading from pipe\n" );
                if ( read( pipe_file_descriptors[0], buf, BUFSIZE ) == -1 ) {
                        perror( "read" ); exit( 1 );
                }
                printf( " CHILD: finished reading\n" );
                printf( " CHILD: read \"%s\"\n", buf );
        } else {
                int i;
                for ( i = 0; i < BUFSIZE; ++i ) {
                        buf[ i ] = i % 64 + '@';
                }
                buf[ BUFSIZE - 1 ] = '\0';
                printf( "PARENT: writing to the pipe\n" );
                if ( write( pipe_file_descriptors[1], buf, BUFSIZE ) == -1 ) {
                        perror( "write" ); exit( 1 );
                }
                printf( "PARENT: finished writing\n" );
                wait( NULL );
        }
        return 0;
}
%]
When I run it while it prints to the terminal, it takes a \emph{very} long
time to show five megabytes of output, but it takes a very short time
to output to the null device, \texttt{/dev/null}.  However, the first
program, \texttt{pipe.c}, runs \emph{much} faster:
%@-
\begin{alltt}
$ \textbf{time ./pipe2}
 CHILD: reading from pipe
PARENT: writing to the pipe
PARENT: finished writing
 CHILD: finished reading
 CHILD: read "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz\{|\}~
\end{alltt}%$
\ldots{} (lots more output)\ldots
\begin{alltt}

$ \textbf{time ./pipe2 > /dev/null}

real    0m0.431s
user    0m0.110s
sys     0m0.030s
$ \textbf{time ./pipe > /dev/null}
 
real    0m0.003s
user    0m0.000s
sys     0m0.000s
\end{alltt}
%@+
  \end{solution}
\item Run the shell script \texttt{signal.sh} in
  program~\vref{prg:signal-shell-example}.
\item Modify it to handle other signals, such as the \texttt{TERM},
  \texttt{HUP} and \texttt{QUIT} signals.  How do you send these
  signals to the program?
  \begin{solution}
\begin{verbatim}
#! /bin/sh

trap "echo 'Please dont interrupt me!'" INT
trap "echo 'Dont quit on me!'" QUIT
trap "echo 'Dont terminate me, Arnie!'" TERM
trap "echo 'Dont hang me up now!'" HUP

echo Enter a string:
read string
echo You entered: $string
\end{verbatim}%$
To send a \texttt{SIGINT}, I just press \key{Control-C}.  To send a
\texttt{SIGQUIT}, I press \key{Control-\bs}.  To send the others, I
can open another terminal window, and either:
\begin{itemize*}
\item Find the process \ID using something like \texttt{ps aux
    \textbar{} grep signals.sh}, or:
\item Use \texttt{killall} with the name of the program.  Here I send
  it a \texttt{SIGHUP} and a \texttt{SIGTERM}:
\begin{alltt}
$ \textbf{killall -HUP signals.sh}
$ \textbf{killall -TERM signals.sh}
\end{alltt}
  
\end{itemize*}
  \end{solution}
\item Modify the C program \texttt{signal.c} in
  program~\vref{prg:signal-example} similarly.
  \begin{solution}
Here is a simple-minded solution:
%[
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <signal.h>
#define MAX_LEN 200

void sigint_handler( int sig ) {
        printf( "Please don\'t interrupt me!!\n" );
}
void sigterm_handler( int sig ) {
        printf( "Don\'t terminate me, Arnie!\n" );
}
void sighup_handler( int sig ) {
        printf( "Don\'t hang me up now!\n" );
}
void sigquit_handler( int sig ) {
        printf( "Don\'t quit on me!\n" );
}

int main( void ) {
        char s[MAX_LEN];

        if ( signal( SIGINT, sigint_handler ) == SIG_ERR ) {
                perror( "signal" );
                exit( 1 );
        }
        if ( signal( SIGTERM, sigterm_handler ) == SIG_ERR ) {
                perror( "signal" );
                exit( 1 );
        }
        if ( signal( SIGHUP, sighup_handler ) == SIG_ERR ) {
                perror( "signal" );
                exit( 1 );
        }
        if ( signal( SIGQUIT, sigquit_handler ) == SIG_ERR ) {
                perror( "signal" );
                exit( 1 );
        }

        printf( "Enter a string:\n" );

        if ( fgets( s, MAX_LEN, stdin ) == NULL )
                perror( "fgets" );
        else 
                printf( "You entered: %s", s );

        return 0;
}
%]
  \end{solution}
\item Write a simple shell script to send signals to the two programs
  \texttt{signal.sh} and \texttt{signal.c}.
  \begin{solution}
    This is a simple solution that assumes that the two programs are
    called \texttt{signals} and \texttt{signals.sh}, and that both are
    already running (in other terminal windows).  Then running this simple
    little script:
\begin{verbatim}
#! /bin/sh

for signal in INT HUP QUIT TERM
do
    killall -${signal} signals
    killall -${signal} signals.sh
done
\end{verbatim}
when run in one window, I see this in the other two windows:
\begin{alltt}
$ \textbf{./signals}
Enter a string:
Please don't interrupt me!!
Don't hang me up now!
Don't quit on me!
Don't terminate me, Arnie!
\end{alltt}%$
and in the other window:
\begin{alltt}
$ \textbf{./signals.sh}
Enter a string:
Please dont interrupt me!
Dont hang me up now!
Dont quit on me!
Dont terminate me, Arnie!
\end{alltt}%$
  \end{solution}
\end{enumerate}

%% \section{References}
%% \label{sec:references}

%%   There are many good sources of information in the library and on the
%%   Web about processes and threads.  Here are some I recommend:
%%   \begin{itemize}
%%   \item\url{http://www.llnl.gov/computing/tutorials/workshops/workshop/pthreads/MAIN.html}

%%   gives a {good online tutorial} about \POSIX threads.
%% \item \url{http://www.humanfactor.com/pthreads/} provides links to a
%%   lot of information about \POSIX threads

%% \item The {best book} about \POSIX threads is
%%   \emph{Programming with POSIX Threads}, David Butenhof,
%%   Addison-Wesley, May 1997.  Even though it was written so long ago,
%%   David wrote much of the \POSIX threads standard, so it really is the
%%   definitive work. It made me laugh, too!
%% \item \emph{Operating Systems: A Modern Perspective: Lab Update}, 2nd
%%   Edition, Gary Nutt, Addison-Wesley, 2002.  A nice text book that
%%   emphasises the practical (like I do!)
%% \end{itemize}

\begin{thebibliography}{widest}
\label{sec:references}
%%   \item[]There are many good sources of information in the library and on the
%%   Web about processes and threads.  Here are some I recommend:

\bibitem[Beej97]{bib:Beej97} \emph{Beej's Guide to Unix Interprocess
    Communication} by Brian ``Beej'' Hall:
  \url{http://www.ecst.csuchico.edu/~beej/guide/ipc/} is the main
  source for this workshop.
\bibitem[Ste92]{bib:Ste92} W. Richard Stevens, \emph{Advanced
    Programming in the UNIX Environment}, Addison-Wesley, 1992, call
  number in our library: QA 76.76 .063 S754 1992
%% \bibitem[links]{bib:links}\url{http://www.humanfactor.com/pthreads/} provides links to a
%%   lot of information about \POSIX threads

%% \bibitem[But97]{bib:But97} The {best book} about \POSIX threads is
%%   \emph{Programming with POSIX Threads}, David Butenhof,
%%   Addison-Wesley, May 1997.  Even though it was written so long ago,
%%   David wrote much of the \POSIX threads standard, so it really is the
%%   definitive work. It made me laugh, too!
%% \bibitem[Nut02]{bib:Nut02} \emph{Operating Systems: A Modern Perspective: Lab Update}, 2nd
%%   Edition, Gary Nutt, Addison-Wesley, 2002.  A nice text book that
%%   emphasises the practical (like I do!)
\end{thebibliography}
\end{document}
