Originally Published: Thursday, 23 August 2001 Author: Subhasish Ghosh
Published to: develop_articles/Development Articles Page: 4/5 - [Printable]

Understanding Linux Kernel Inter-process Communication: Pipes, FIFO & IPC (Part 1)

In this article, part one of a two part article, the prolific and talented Subhasish returns to give Linux.com readers another trip into understanding Linux kernel behavoir and programming. There's a lot of information covered here for free, so hang up your hat and have fun. Part 2 of Understanding Linux Kernel Inter-process Communication will be published tomorrow.

FIFOs  << Page 4 of 5  >>

FIFOs

A couple of weeks back one of my friends asked: "Is 'FIFO' same as a 'pipe'"? She appeared to be confused. No, pipes and FIFOs are different entities. Just as I had discussed "processes" and "threads" earlier. So, though pipes and FIFOs are related, but NO, they are not the same entities. So, the question that comes up is: What are FIFOs? And how are they "better" than pipes? Although pipes are a simple, flexible and efficient communication mechanism, they suffer from one major drawback. There is no way to open an already existing pipe. This makes it impossible for two arbitrary processes to share the same pipe. So far, we have only been able to pass data between programs that are related, i.e. programs that have been started from a common ancestor process. But what if two unrelated processes want to be able to exchange data? We do this using FIFOs, often referred to as "named pipes". A named pipe is a special file that behaves like the unnamed pipes we have seen so far. Also called FIFOs (i.e. "first in, first out"; the first byte written into the special file is also the first byte that will be read).

FIFO files are similar to device files. They have a disk inode, but they do not make use of data blocks. FIFOs are similar to unnamed pipes in that they also include a kernel buffer to temporarily store the data exchanged by two or more processes. Now the question is, how to create a "named pipe"? We can create named pipes from the command line and from within a program. But the creation of named pipes can be a bit confusing. But don't worry, read on. A process creates a FIFO by issuing a mknod() system call, passing to it as parameters the pathname of the new FIFO and the value S_IFIFO(0x1000) logically ORed with the permission bit mask of the new file. But there's a problem in this. The mknod() system call is NOT in the X/Open command list, so may not be available on all UNIX systems. Thus, POSIX introduces a system call called mkfifo(), specifically designed to create a FIFO. This call is implemented in GNU/Linux, as in System V Release 4 (SVR4), as a C library function that invokes mknod(). The preferred command line method is to use:

# mkfifo filename

Note: All readers should note that some older versions of UNIX only have the mknod() command. X/Open Issue 4 Version 2 has the mknod function call, but NOT the command. GNU/Linux supports both mknod and mkfifo. (See! I always say: Linux is the best!) Let's now take a look at the functions. These are:

#include <sys/types.h>
#include <sys/stat.h>

int mkfifo (const char* filename, mode_t mode);
int mknod( const char* filename, mode_t mode | S_IFIFO, (dev_t)0);

Since I like dealing with POSIX standards, and also as Linux supports mkfifo, we will be using the mkfifo() system call in this article from now on, instead of mknod(). Let's now create a 'named pipe' and see what's in store for us. So, open vi, type in this source code, and save the file. The code:

/* Creating a Named Pipe:
By: Subhasish Ghosh
Date: August 17th 2001
Place: Calcutta, WB, INDIA
E-mail:
subhasish_ghosh@linuxmail.org
*/

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>

int main()
{
int res = mkfifo("/tmp/subhasish", 0777);
if (res = = 0) printf ("FIFO created successfully\n");
exit (EXIT_SUCCESS);
}

When we compile and run this program, it creates a named pipe for us (look out for the output "FIFO created successfully" on the screen). We can look for the pipe with the command:

# ls -lF /tmp/subhasish
prwxr-xr-x 1 root root 0 Dec 10 14:55 /tmp/subhasish |

Notice that the first character is a 'p', indicating a pipe. The '|' symbol at the end is added by the ls command's -F option and also indicates a pipe. The program uses the mkfifo() function to create a special file. Although we have asked for the mode of 0777, this is altered by the user mask (umask) setting of 022, and thus the resulting file has mode 755. For removing the FIFO, just issue a rm command or use the "unlink" system call from within a program. Unlike a pipe created with the pipe() system call, a FIFO exists as a named file, not as an open file descriptor. Thus it must be opened before it can be read from or written to. One opens and closes a FIFO using the open() and close() functions, but with some additional functionality. The open() call is passed the path name of the FIFO, rather than of a regular file. Now, for opening a FIFO, we have four possible cases. Let's look into the matter in a bit more detail.

If we wish to pass data in both directions between programs, it's much better to use either a pair of FIFOs or pipes, one for each direction. The main difference between opening a FIFO and a regular file is the use of the open_flag (the second parameter to open), with the option O_NONBLOCK. There exist 4 possible (and definitely legal) combinations of O_RDONLY, O_WRONLY and the O_NONBLOCK flags. Let's see what each combination has to offer:

1) open (const char *path, O_RDONLY);
2) open (const char *path, O_RDONLY | O_NONBLOCK);
3) open (const char *path, O_WRONLY);
4) open (const char *path, O_WRONLY | O_NONBLOCK);

In case of 1), the open call will block, in other words, will not return until a process opens the same FIFO for writing.
In case of 2), the open call will return immediately, even if the FIFO had not been opened for writing by any process.
In case of 3), the open call will block until a process opens the same FIFO for reading.
In case of 4), the open call will return immediately, but if no process has the FIFO for reading, open will return an error, -1.





FIFOs  << Page 4 of 5  >>