<H2>Interprocess Communication</H2>
<UL>
   <LI> Networking involves communication between processes.
   <LI> Not all interprocess communication involves networking.
   <LI> Typically, IPC services are provided by the Operating System.
</UL>
<H2>IPC - Single System</H2>
<IMG SRC=ipc1.gif>

<H2>IPC - Different Systems</H2>
<IMG SRC=ipc2.gif>

<H2>Single System IPC</H2>
<UL>
   <LI> Pipe: one-way data stream
   <LI> FIFO: special kind of pipe
   <LI> Message Queue: message passing (not a data stream)
   <LI> Semaphores: Synchronization primitive
   <LI> Shared Memory: data does not go through the kernel (Operating System).
</UL>
<H2>File Locking</H2>
<UL>
   <LI> Allows cooperating processes to share a resource safely (mutual 
exclusion).
   <LI> Example:
   <UL>
      <LI> integer count kept in a file
      <LI> the count is updated by a program every time some event occurs
      <LI> without file locking the value can be corrupted.
   </UL>
</UL>
<H2>Advisory vs. Mandatory Locking</H2>
<UL>
   <LI> Advisory - operating system keeps track of file locks but does not 
enforce access restrictions. Requires cooperating processes.

   <LI> Mandatory - operating system checks every read and write, withholding services when appropriate.
</UL>

<H2>Record Locking</H2>
<UL>
   <LI> Lock part of a file, in Unix this typically means a range of character positions within the file.
   <LI> Multiple processes can use the same file at the same time as long as they are working on different parts of the file.
</UL>

<H2>lockf() sytem call (Sys V)</H2>
<UL>
   <LI> Single system call for all file locking services:
   <UL>
      <LI> lock a region of a file
      <LI> unlock a region of a file
      <LI> test and lock a region (non-blocking)
      <LI> test to see if a region is locked
   </UL>
</UL>
<H2>Blocking vs. Non-Blocking System Calls</H2>
<UL>
   <LI> A blocking system call does not return until the requested operation is possible (or an error occurs). The calling process is put to sleep until the operation is possible.
   <LI> A non-Blocking - system call returns if the operation is not possible immediately. There must be some way for the calling process to determine what happened !
</UL>
<H2>Back to lockf()</H2>
<PRE>int lockf( int fd, int function, long size)</PRE>
fd is a file descriptor (small integer)<BR>
function can be:
<UL>
	<LI> F_ULOCK	unlock a region
	<LI> F_LOCK lock a region (blocking)
	<LI> F_TLOCK lock a region (non-blocking)
	<LI> F_TEST test a region
</UL>

<H2>lockf() example</H2>
<PRE>
/* lock a file */
if ( lockf(file, F_LOCK, 0) ==1 )
  /* error can't lock the file */

/* unlock a file */
if ( lockf(file, F_ULOCK, 0) ==1 )
  /* error can't unlock the file */
</PRE>

<H2>POSIX file locking</H2>
<UL>
   <LI> POSIX supports advisory file locking.
   <LI> All file locking services provided via the fcntl() system call.
   <LI> Additional services (beyond lockf):
   <UL>
      <LI> shared locks (read locks)
      <LI> can find out what process has a lock (pid)
   </UL>
</UL>

<H2>Pipes</H2>
<UL>
   <LI> One-way stream of data
   <LI> Kernel buffers the data
</UL>
<IMG SRC=ipc3.gif>

<H2>pipe() system call</H2>
<CODE>	int pipe( int filedes[2])</CODE>
<UL>
   <LI> filedes is a 2 element array of file descriptors - pipe fills in the 
values.
   <LI> return value is less than 0 if an error occurred.
</UL>

<H2>pipe()</H2>
<IMG SRC=ipc4.gif>

<H2>pipe() followed by fork()</H2>
<IMG SRC=ipc5.gif>

<H2>Cleanup with close()</H2>
<IMG SRC=ipc6.gif>


<H2>2-way communication</H2>
<UL>
   <LI> Need 2 pipes to support 2-way communication between parent process and child process.
   <LI> Both pipes must be created before the fork()
</UL>

<H2>Creating 2-way communication</H2>
<PRE>
int fd_a[2], fd_b[2];
if ( (pipe(fd_a)<0) || (pipe(fd_b)<0) )
   /* error opening pipes */
if (fork()==0){
   /* child process */
   close(fd_a[0]); close(fd_b[1]);
   /* write to parent via fd_a[1], read from fd_b[0] */
} else {
   /* parent process */
   close(fd_a[1]); close(fd_b[0]);
   /* write to child via fd_b[1], read from fd_a[0] */
}
</PRE>
<H2>2-way communication</H2>
<IMG SRC=ipc7.gif>

<H2>IPC using pipes </H2>
<UL>
   <LI> Processes must be closely related (must have a common ancestor).
   <LI> Unix shells use pipes extensively to pass the output of one process as input to another process.
   <LI> ls | sort  | more
</UL>

<H2>FIFOs - First In, First Out </H2>
<UL>
   <LI> Also known as Named Pipe
   <LI> Data stream buffered by the kernel
   <LI> A FIFO has a name associated with it - this makes IPC between independent processes possible.
   <LI> The name is a Unix pathname.
</UL>

<H2>mknod() system call</H2>
<UL>
   <LI> A FIFO is created with the mknod() system call.

    <PRE>     int mknod(char *pathname,int mode,int dev)</PRE>
    <UL>
	<LI> pathname is a Unix pathname</H2>
	<LI> mode specifies the access mode (permissions)
        <LI> dev is ignored (mknod is used for other things)
    </UL>
   <LI> A FIFO can also be created with mkfifo() system call (POSIX).
</UL>

<H2>opening a FIFO</H2>
<UL>
   <LI> the open() system call is used to open a FIFO for reading or writing.
   <LI> opening a FIFO for reading will block until a process opens the FIFO for writing.
   <LI> opening a FIFO for writing will block until a process opens the FIFO for reading.
   <LI> Use the O_NDELAY flag when opening a FIFO to avoid the problem (O_NONBLOCK for POSIX).
</UL>

<H2>Rules for reading FIFOs & Pipes</H2>
<UL>
   <LI> any read() requesting more data than exists in the FIFO (pipe) 
returns less than the requested amount of data.
   <LI> read from empty FIFO (pipe) returns:
   <LI>		. 0 if no process has the FIFO (pipe) open for writing End-of-File condition.
   <LI>		. If non-blocking mode is set read() returns a 0 whenever there is no data available.
</UL>

<H2>Rules for writing FIFOs & Pipes</H2>
<UL>
   <LI> writes of less than the capacity of the FIFO (pipe) are atomic.
   <LI> a write to a FIFO or pipe wich is not open for reading by any process generate a SIGPIPE and write() returns an error.
   <LI> a write to a full FIFO or pipe will block (unless  non-blocking mode).
</UL>
<H2>Streams vs. Messages</H2>
<UL>
   <LI> Stream I/O
   <UL>
      <LI> no record boundaries
      <LI> reading process cannot tell how bytes were written (how many bytes at a time).
      <LI> O.S.  does buffering
      <LI> Any structure to the data must be supported by the application
   </UL>
</UL>

<H2>Streams vs. Messages</H2>
<UL>
   <LI> Message based I/O:
   <UL>
      <LI> structured data
      <LI> each read corresponds to a write
      <LI> depending on the message service, the order of messages may not be preserved.
   </UL>
</UL>

<H2>System V IPC</H2>
<UL>
   <LI> The book describes Sys V message queues, semaphores and 
shared memory.
   <LI> We won't cover this material
   <LI> Could be a case study:
   <UL>
      <LI> Review Sys V IPC programming interface
      <LI> describe how it could be done  with a network.
   </UL>
</UL>

<H2>FIFO Example</H2>
<UL>
   <LI> Client - Server architecture
   <LI> Need 2 FIFOs for 2-way communication
   <LI> Server accessible via well known address (FIFO pathname).
   <LI> Client creates FIFO and sends server the name.
</UL>
<H2>FIFO Example </H2>
<IMG SRC=ipc8.gif>

<H2>Server</H2>
<IL>
<LI> opens well known FIFO (fifo_wk) for reading.
<LI> reads name of temporary FIFO (fifo_tmp) from fifo_wk.
<LI> opens fifo_tmp for writing.
<LI> receives request from fifo_wk and sends response to fifo_tmp.
<LI> close fifo_tmp and go back to step 1.
</IL>

<H2>Client</H2>
<IL>
<LI> create temporary FIFO fifo_tmp.
<LI> open well known FIFO fifo_wk for writing.
<LI> write name of temporary FIFO to fifo_wk.
<LI> open fifo_tmp for reading.
<LI> write request to fifo_wk
<LI> read response from fifo_tmp.
<LI> close FIFOs and delete fifo_tmp.
</IL>

<H2>Deadlock</H2>
<UL>
   <LI> By default, an open() call to a FIFO will block.
   <LI> The order of open() calls is important !!!
   <LI> Can avoid some problems with  O_NONBLOCK option to open():
<PRE>
      fd = open(path, O_NONBLOCK | O_RDONLY); 
</PRE>
</UL>

<H2>Homework #1</H2>
<UL>
   <LI> Develop a FIFO based Client-Server system  for looking up uids.
   <LI> Client sends the server a login name (the request).
   <LI> Server sends back a uid (the response).
</UL>

<H2>Homework #1 (cont.)</H2>
<UL>
   <LI> Server uses a well known FIFO.
   <LI> You can create the well known FIFO with the Unix command /etc/mknod.
   <LI> Test the well known FIFO with the Unix cat command.
   <LI> Use the code in the book as a starting point.
</UL>

