Implementation of Pipe in Linux

Implementation of Pipe in Linux

INTRODUCTION

In Linux, pipes are a fundamental mechanism for inter-process communication (IPC), enabling data to flow directly from one process to another. A pipe connects the standard output of one process to the standard input of another, allowing users and developers to build powerful and flexible workflows. Most Linux users are familiar with pipes through the shell’s | operator, commonly used to link commands like ls | sort. However, beyond basic shell usage, Linux also provides low-level system calls that allow programmers to create and control pipes programmatically for more sophisticated communication between processes.

Pipes operate on a First-In-First-Out (FIFO) principle, ensuring that the data written first is also read first. The pipe() system call is used to create a pair of connected file descriptors, one for reading and one for writing. Typically, pipes are used between related processes, such as a parent and its child created through fork(). Proper handling of these file descriptors, including closing unused ends, is essential to avoid resource leaks and ensure efficient communication.

 

Implementation of Pipe  in Linux

  • We use the term pipe to mean connecting a data flow from one process to another.
  • Generally you attach, or pipe, the output of one process to the input of another.
  • Most Linux users will already be familiar with the idea of a pipeline, linking shell commands together so that the output of one process is fed straight to the input of another.
  • For shell commands, this is done using the pipe character to join the commands, such as

Ex:cmd1 | cmd2

  • The output of first command is given as input to the second command.
  • Examples:

– ls | wc

– who | sort

– cat file.txt | sort | wc

How this works?

 

Implementation of Pipe in Linux

 

The pipe System call

The lower-level pipe function provides a means of passing data between two programs, without the overhead of invoking a shell to interpret the requested command. It also gives you more control over the reading and writing of data.

The pipe function has the following prototype:

#include

int pipe(int file_descriptor[2]);

  1. 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.
  2. The two file descriptors returned are connected in a special way.
  3. 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.
  4. 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.

The Pipe

 

Implementation of Pipe  in Linux

 

 

The write system call

#include<unistd,h>

 size_t write(int fildes, const void *buf, size_t nbytes);

  1. It arranges for the first nbytes bytes from buf to be written to the file associated with the file descriptor fildes.
  2. It returns the number of bytes actually written. This may be less than nbytes if there has been an error in the file descriptor. If the function returns 0, it means no data was written; if it returns –1, there has been an error in the write call.

The read system call

#include

 size_t read(int fildes, void *buf, size_t nbytes);

  1. It reads up to nbytes bytes of data from the file associated with the file descriptor fildes and places them in the data area buf.
  2. It returns the number of data bytes actually read, which may be less than the number requested. If a read call returns 0, it had nothing to read; it reached the end of the file. Again, an error on the call will cause it to return –1.

 Steps to Implement Pipe Between Related Processes:

  1. Create a pipeusing the pipe(fd) system call.
  2. Call fork()to create a child process.
  3. Close the unused endof the pipe in each process:
  • Parent closes the write endif it reads.
  • Child closes the read endif it writes.
    1. Write datato the pipe from one process.
    2. Read datafrom the pipe in the other process.
    3. Close the used endsafter communication is done.
    4. Wait for the childusing wait() if needed (optional but good practice).