Interprocess Communication - Networking involves communication between processes. - Not all interprocess communication involves networking. - Typically, IPC services are provided by the Operating System. IPC - Single System IPC - Different Systems Single System IPC - Pipe: one-way data stream - FIFO: special kind of pipe - Message Queue: message passing (not a data stream) - Semaphores: Synchronization primitive - Shared Memory: data does not go through the kernel (Operating System). File Locking - Allows cooperating processes to share a resource safely (mutual exclusion). - Example: . integer count kept in a file . the count is updated by a program every time some event occurs . without file locking the value can be corrupted. Advisory vs. Mandatory Locking - Advisory - operating system keeps track of file locks but does not enforce access restrictions. Requires cooperating processes. - Mandatory - operating system checks every read and write, withholding services when appropriate. Record Locking - Lock part of a file, in Unix this typically means a range of character positions within the file. - Multiple processes can use the same file at the same time as long as they are working on different parts of the file. lockf() sytem call (Sys V) - Single system call for all file locking services: . lock a region of a file . unlock a region of a file . test and lock a region (non-blocking) . test to see if a region is locked Blocking vs. Non-Blocking System Calls - 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. - 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 ! Back to lockf() int lockf( int fd, int function, long size) fd is a file descriptor (small integer) function can be: F_ULOCK unlock a region F_LOCK lock a region (blocking) F_TLOCK lock a region (non-blocking) F_TEST test a region (blocking) lockf() example /* 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 */ POSIX file locking - POSIX supports advisory file locking. - All file locking services provided via the fcntl() system call. - Additional services (beyond lockf): . shared locks (read locks) . can find out what process has a lock (pid) Pipes - One-way stream of data - Kernel buffers the data pipe() system call int pipe( int filedes[2]) - filedes is a 2 element array of file descriptors - pipe fills in the values. - return value is less than 0 if an error occurred. pipe() pipe() followed by fork() Cleanup with close() 2-way communication - Need 2 pipes to support 2-way communication between parent process and child process. - Both pipes must be created before the fork() Creating 2-way communication 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] */ } 2-way communication IPC using pipes - Processes must be closely related (must have a common ancestor). - Unix shells use pipes extensively to pass the output of one process as input to another process. - ls | sort | more FIFOs - First In, First Out - Also known as Named Pipe - Data stream buffered by the kernel - A FIFO has a name associated with it - this makes IPC between independent processes possible. - The name is a Unix pathname. mknod() system call - A FIFO is created with the mknod() system call. int mknod(char *pathname,int mode,int dev) - pathname is a Unix pathname - mode specifies the access mode (permissions) - dev is ignored (mknod is used for other things) opening a FIFO - the open() system call is used to open a FIFO for reading or writing. - opening a FIFO for reading will block until a process opens the FIFO for writing. - opening a FIFO for writing will block until a process opens the FIFO for reading. - Use the O_NDELAY flag when opening a FIFO to avoid the problem (O_NONBLOCK for POSIX). Rules for reading FIFOs & Pipes - any read() requesting more data than exists in the FIFO (pipe) returns less than the requested amount of data. - read from empty FIFO (pipe) returns: . 0 if no process has the FIFO (pipe) open for writing - End-of-File condition. . If non-blocking mode is set - read() returns a 0 whenever there is no data available. Rules for writing FIFOs & Pipes - writes of less than the capacity of the FIFO (pipe) are atomic. - a write to a FIFO or pipe wich is not open for reading by any process generate a SIGPIPE and write() returns an error. - a write to a full FIFO or pipe will block (unless non-blocking mode). Streams vs. Messages - Stream I/O . no record boundaries . reading process cannot tell how bytes were written (how many bytes at a time). . O.S. does buffering . Any structure to the data must be supported by the application Streams vs. Messages - Message based I/O: . structured data . each read corresponds to a write . depending on the message service, the order of messages may not be preserved. System V IPC - The book describes Sys V message queues, semaphores and shared memory. - We won't cover this material - Could be a case study: . Review Sys V IPC programming interface . describe how it could be done with a network. FIFO Example - Client - Server architecture - Need 2 FIFOs for 2-way communication - Server accessible via well known address (FIFO pathname). - Client creates FIFO and sends server the name. FIFO Example Server 1. opens well known FIFO (fifo_wk) for reading. 2. reads name of temporary FIFO (fifo_tmp) from fifo_wk. 3. opens fifo_tmp for writing. 4. receives request from fifo_wk and sends response to fifo_tmp. 5. close fifo_tmp and go back to step 1. Client 1. create temporary FIFO fifo_tmp. 2. open well known FIFO fifo_wk for writing. 3. write name of temporary FIFO to fifo_wk. 4. open fifo_tmp for reading. 5. write request to fifo_wk 6. read response from fifo_tmp. 7. close FIFOs and delete fifo_tmp. Deadlock - By default, an open() call to a FIFO will block. - The order of open() calls is important !!! - Can avoid some problems with O_NONBLOCK option to open(): . fd = open(path, O_NONBLOCK | O_RDONLY); Homework #1 - Develop a FIFO based Client-Server system for looking up uids. - Client sends the server a login name (the request). - Server sends back a uid (the response). Homework #1 (cont.) - Server uses a well known FIFO. - You can create the well known FIFO with the Unix command /etc/mknod. - Test the well known FIFO with the Unix cat command. - Use the code in the book as a starting point.