A pipe is a method of connecting the standard output of one process to the standard input of another. Pipes are the eldest of the IPC tools, having been around since the earliest incarnations of the UNIX operating system. They provide a method of one-way communications (hence the term half-duplex) between processes.
This feature is widely used, even on the UNIX command line (in the shell).
When a process creates a pipe, the kernel sets up two file descriptors for use by the pipe. One descriptor is used to allow a path of input into the pipe (write), while the other is used to obtain data from the pipe (read). At this point, the pipe is of little practical use, as the creating process can only use the pipe to communicate with itself.
While a pipe initially connects a process to itself, data traveling through the pipe moves through the kernel. Under Linux, in particular, pipes are actually represented internally with a valid inode. Of course, this inode resides within the kernel itself, and not within the bounds of any physical file system. This particular point will open up some pretty handy I/O doors for us, as we will see a bit later on.
At this point, the creating process typically forks a child process. Since a child process will inherit any open file descriptors from the parent, we now have the basis for multiprocess communication (between parent and child). It is at this stage, that a critical decision must be made. In which direction do we desire data to travel? Does the child process send information to the parent, or vice-versa? The two processes mutually agree on this issue, and proceed to “close” the end of the pipe that they are not concerned with.
To access a pipe directly, the same system calls that are used for low-level file I/O can be used (recall that pipes are actually represented internally as a valid inode).
To send data to the pipe, we use the write() system call, and to retrieve data from the pipe, we use the read() system call. Remember, low-level file I/O system calls work with file descriptors! However, keep in mind that certain system calls, such as lseek(), do not work with descriptors to pipes.
To create a simple pipe with C, we make use of the pipe() system call. It takes a single argument, which is an array of two integers, and if successful, the array will contain two new file descriptors to be used for the pipeline.
System Call: pipe();
Prototype; int pipe(int fd);
RETURNS: 0 on success -1 on error: errno = EMFILE (no free descriptors)
EMFILE (system file table is full)
EFAULT (fd array is not valid)
NOTES: fd is set up for reading, fd is set up for writing
The popen() function creates a pipe between the calling program and the command to be executed. The arguments topopen() are pointers to null-terminated strings. The com-mand argument consists of a shell command line. The modeargument is an I/O mode, either r for reading or w for writing. The value returned is a stream pointer such that one can write to the standard input of the command, if the I/Omode is w, by writing to the file stream and one can read from the standard output of the command, if the I/O mode is r, by reading from the file stream.
The pclose() function closes a stream opened by popen() by closing the pipe. It waits for the associated process to terminate and returns the termination status of the process running the command language interpreter. This is the value returned by waitpid(2).
Simple Pipes or Lowlevel Pipes
/* Program to demonstrate the creation and use of simple/low level pipe.
* This program creates a pipe that connects the child process with its parent process.
* Here the child process writes ‘REQUEST FROM CHILD PROCESS.’ on to the pipe
which is read by the parent process.
* The function ‘fork()’ is a system call used to create a child process.
* This module can be compiled using ‘cc simplepipe.c’ and executed using ‘./a.out’
//array to store the pipe pointers returned by the pipe() function.
//variable to store the child process id.
//creating a pipe
//creating a child process.
printf(“\nThe child process is writing.\n”);
//closing the read pointer.
//writing on to the pipe.
write(pipe_pointer,”REQUEST FROM CHILD PROCESS.”,sizeof(“REQUEST FROM CHILD PROCESS.”));
printf(“\nThe parent process is reading.\n”);
//closing the write pointer.
//reading from the pipe.
printf(“\nThe parent has read:\n\n** %s **\n”,message);
/* Program to demonstrate the creation and use of formatted pipe.
* This program creates a formatted pipe which is connected to the system process
denoted by the command ‘CMD’.
* The pipe is established for reading and the read content is displayed.
* This module can be compiled using ‘cc formattedpipe.c’ and executed ‘./a.out’.*/
#define CMD “cal”
//creating a formatted pipe.
//closing the pipe.