Named Pipes: FIFOs

FIFO

A named pipe is a special type of file (remember that everything in Linux is a file!) that exists as a name in the file system but behaves like the unnamed
pipes that we’ve met already.

We can create named pipes from the command line and from within a program. Historically, the command line program for creating them was mknod:

$ mknod filename p

However, the mknod command is not in the X/Open command list, so it may not be available on all UNIX-like systems. The preferred command line method is to use

$ mkfifo filename

Some older versions of UNIX only had the mknod command. X/Open Issue 4 Version 2 has the mknod function call, but not the command line program. Linux, friendly as ever, supplies both mknod and mkfifo.

From inside a program, we can use two different calls:

#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);

Like the mknod command, you can use the mknod function for making many special types of files. Using a dev_t value of 0 and ORing the file access mode with S_IFIFO is the only portable use of this function that creates a named pipe. We’ll use the simpler mkfifo function in our examples


#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
int main()
{
int res = mkfifo(“/tmp/my_fifo”, 0777);
if (res == 0) printf(“FIFO created\n”);
exit(EXIT_SUCCESS);
}



We can look for the pipe with

$ ls -lF /tmp/my_fifo

prwxr-xr-x 1 vineet embedyourcareer  0 march 18 14:55 /tmp/my_fifo|

Notice that the first character of output 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.

How It Works

The program uses the mkfifo function to create a special file. Although we ask for a mode of 0777, this is altered by the user mask (umask) setting (in this case 022), just as in normal file creation, so the resulting file has mode 755. If your umask is set differently, for example to 0002, you will see different permissions on the created file.
We can remove the FIFO just like a conventional file by using the rm command, or from within a program by using the unlink system call.


Basics of Inter process communication- PIPE


Inter Process Communication


PIPE:

We use the term pipe when we connect a data flow from one process to another. Generally we attach, or pipe, the output of one process to the input of another.

Most Linux users will already be familiar with the idea of linking shell commands together, so that the output of one process is fed straight to the input of another. For shell commands, this is entered as
cmd1 | cmd2



The shell arranges the standard input and output of the two commands, so that
The standard input to cmd1 comes from the terminal keyboard.
The standard output from cmd1 is fed to cmd2 as its standard input.
The standard output from cmd2 is connected to the terminal screen.



What the shell has done, in effect, is reconnect the standard input and output streams so that data flows from the keyboard input through the two commands and is then output to the screen.



The PIPE Call:

The pipe function has the following prototype:

#include <unistd.h>
int pipe(int file_descriptor[2]);

pipe is passed (a pointer to) an array of two integer file descriptors. It fills the array with two new file descriptors and returns a zero. On failure, it returns -1 and sets errno to indicate the reason for failure. Errors defined in the Linux manual page (section 2 of the manual) are

EMFILE: Too many file descriptors are in use by the process.
ENFILE: The system file table is full.
EFAULT: The file descriptor is not valid.

The two file descriptors returned are connected in a special way. Any data written to file_descriptor[1] can be read back from file_descriptor[0]. The data is processed in a first in, first out basis, usually abbreviated to FIFO. This means that if you write the bytes 1, 2, 3 to file_descriptor[1], reading from file_descriptor[0] will produce 1, 2, 3. This is different from a stack, which operates on a last in, first out basis, usually abbreviated to LIFO.




Here’s a program, pipe1.c, that uses pipe to create a pipe.


Type the following code.

Note the file_pipes pointer, which is passed to the pipe function as a parameter.

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main()
{
int data_processed;
int file_pipes[2];
const char some_data[] = “123”;
char buffer[BUFSIZ + 1];

memset(buffer, ‘\0’, sizeof(buffer));

if (pipe(file_pipes) == 0)
{
data_processed = write(file_pipes[1], some_data, strlen(some_data));
printf(“Wrote %d bytes\n”, data_processed);
data_processed = read(file_pipes[0], buffer, BUFSIZ);
printf(“Read %d bytes: %s\n”, data_processed, buffer);
exit(EXIT_SUCCESS);
}

exit(EXIT_FAILURE);
}


When we run this program, the output is
$ ./pipe1
Wrote 3 bytes
Read 3 bytes: 123



How It Works

The program creates a pipe using the two file descriptors file_pipes. It then writes data into the pipe using the file descriptor file_pipes and reads it back from file_pipes. Notice that the pipe has some internal buffering that stores the data in between the calls to write and read.

You should be aware that the effect of trying to write using file_descriptor, or read using file_descriptor, is undefined, so the behavior could be very strange and may change without warning. On the authors’ systems, such calls fail with a –1 return value, which at least ensures that it’s easy to catch this mistake.

At first glance, this example of a pipe doesn’t seem to offer us anything that we couldn’t have done with a simple file. The real advantage of pipes comes when you wish to pass data between two processes.