Programming with FIFO: mkfifo(), mknod()

FIFOs can be created from the shell. But they can also be created using programs. There are two ways by which FIFOs can be created from the program

Creating a FIFO

1. mknod

Syntax

int mknod(const char *pathname, mode_t mode, dev_t dev);

where pathname corresponds to the fifo name, mode corresponds to the file permissions. Since mknod can be used to create a regular file, block or charcter special files and fifo. We have to specify the file type. Corresponding to FIFO: the file type is S_IFIFO.

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

int main(int argc, char *argv[]){
     int result;
     if (argc != 2) {
             fprintf(stderr, "Usage: ./a.out fifoname\n");
             exit (1);
     }

     result = mknod (argv[1], S_IRUSR| S_IWUSR|S_IFIFO, 0);
     if (result < 0) {
          perror ("mknod");
          exit (2);
       }
  }

Here we wish to give both read and write permissions to the user. So we specified S_IRUSR | S_IWUSR| S_IFIFO in the mode. If the file type is S_IFCHR or S_IFBLK then dev is checked; otherwise it is ignored. So we passed 0 as the argument.

2. mkfifo

Syntax

int mkfifo(const char *pathname, mode_t mode);

where pathname correspnds to fifo name and mode corresponds to file mode.

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

int main(int argc, char *argv[]){
     int result;

     if (argc != 2) {
          fprintf(stderr, "Usage: ./a.out fifoname\n");
          exit (1);
     }

    result = mkfifo (argv[1], S_IRUSR| S_IWUSR);
     if (result < 0) {
          perror ("mkfifo");
          exit (2);
      }
  }

Here we need not explicitly specify the file type S_IFIFO. You can (if you wish) specify S_IFIFO in the mode.

 

Using Pipes in Linux Processes

Pipes can be used in threads and processes. The program below demonstrates how pipes can be used in processes. A new process can be created using the system call fork(). It returns two differnt values to the child and parent. The value 0 is returned to the child (new) process and the PID (Process ID) of the child is returned to the parent process. This is used to distinguish between the two processes. In the program given below, the child process waits for the user input and once an input is entered, it writes into the pipe. And the parent process reads from the pipe.

A sample program to demonstrate how pipes are used in Linux Processes

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

#define MSGLEN  64

int main(){
    int     fd[2];
    pid_t pid;
    int     result;

    //Creating a pipe
    result = pipe (fd);
    if (result < 0) {
        //failure in creating a pipe
        perror("pipe");
        exit (1);
    }

    //Creating a child process
    pid = fork();
    if (pid < 0) {
         //failure in creating a child
         perror ("fork");
         exit(2);
    }

    if (pid == 0) {
        //Child process
         char message[MSGLEN];

          while(1) {
                    //Clearing the message
                    memset (message, 0, sizeof(message));
                    printf ("Enter a message: ");
                    scanf ("%s",message);

                    //Writing message to the pipe
                    write(fd[1], message, strlen(message));
            }
            exit (0);
    }
    else {
        //Parent Process
         char message[MSGLEN];

         while (1) {
                    //Clearing the message buffer
                    memset (message, 0, sizeof(message));

                    //Reading message from the pipe
                   read (fd[0], message, sizeof(message));
                    printf("Message entered %s\n",message);
            }

            exit(0);
     }
}

Note here that the pipe() system call was called before the system call fork(). The buffer allocated to the pipe is accessible to both the processes.

 

FIFO – Named pipes: mkfifo, mknod

Pipes are commonly used for interprocess communication. But the major disadvantage of pipes is that they can be used only by one process (there are readers and writers within the same process) or the processes which share the same file descriptor table (normally the processes and the child processes or threads created by them). Thus pipes have this big limitation: they cannot pass information between unrelated processes. This is because they do not share the same file descriptor table. But if names are given to the pipes, then one would be able to read or write data to them just like a normal file. The processes need not even share anything with each otherFIFO (First In First Out) are also called named pipes. The main features of FIFO are
1. It implements FIFO feature of the pipes
2. They can be opened just like normal files using their names
3. Data can be read from or written to the fifo

Working with FIFO in a Shell

Creating a FIFO

mkfifo

creates fifo- the named pipes

Syntax

mkfifo [options] fifo_name

Example

$ mkfifo fifo

There is one more way by which we can FIFO using mknod. mknod is used to create block or character special files.

$ mknod [OPTION]... NAME TYPE

To create a FIFO fifo1

$ mknod fifo1 p

where p coressponds to file type : pipe (remember FIFO is a named pipe).

Reading/ Writing data from/to a FIFO
Let’s open two terminals
In the first terminal

$ cat > fifo

we are experimenting with the FIFOThis is second line. After opening the fifo in the second terminal for readingusing cat, you will notice the above two lines displayed there.
Now open the second terminal and go to the directory containing the FIFO ‘fifo’

$ cat fifo

we are experimenting with the FIFOThis is second line. After opening the fifo in the second terminal for reading
Now keep on writing to the first terminal. You will notice that every time you press enter, the coressponding line appears in the second terminal.

Pressing CTRL+D in the first terminal terminates writing to the fifo. This also terminates the second process because reading from the fifo now generates a “BROKEN PIPE” signal. The default action for this is to terminate the process.

Let us now see the details of the file ‘fifo’

$ ls -l fifo
prw-r--r-- 1 user user 0 Feb 14 10:05 fifo

The p in the beginning denotes that it is a pipe.

Let’s see more details about the pipe using stat

$ stat fifo
File: `fifo'Size: 0               Blocks: 0          IO Block: 4096   fifo
Device: fd00h/64768d    Inode: 1145493     Links: 1
Access: (0644/prw-r--r--)  Uid: (    0/    user)   Gid: (    0/    user)
Access: 2008-02-14 10:05:49.000000000 +0530
Modify: 2008-02-14 10:05:49.000000000 +0530
Change: 2008-02-14 10:05:49.000000000 +0530

If you notice carefully, FIFOs just like a normal file possess all the details like inode number, the number of links to it, the access, modification times, size and the access permissions.

As in the case of pipes, there can be multiple readers and writers to a pipe. Try opening multiple terminals to read from and write to a pipe.