Flylib.com

Books Software

 
 
 

Section 9.9. Pipes


9.9. Pipes

Ever since pipes were introduced in Third Edition UNIX (1973), they have been an integral feature of Unix systems. The Unix program-stream redirection facility uses pipes. Therefore, Unix shells use pipes extensively. Mac OS X provides the pipe() system call, which allocates and returns a pair of file descriptors: The first is the read end , and the second is the write end . The two descriptors can provide an I/O stream between two processes, thus serving as an IPC channel. However, pipes have several limitations, some of which may be rather severe for certain applications.

  • Pipes are possible only between related processesthat is, those with a common ancestor .

  • The kernel buffer corresponding to a pipe consumes kernel memory.

  • Pipes support only untyped byte streams.

  • Historically, pipes have allowed only unidirectional data flow. The Single UNIX Specification allows but does not require full-duplex pipes.

  • Only writes below PIPE_BUF bytes in size are guaranteed to be atomic. PIPE_BUF is 512 bytes on Mac OS X. The fpathconf() system call can be used to retrieve the value of PIPE_BUF given a pipe descriptor.

  • You can use pipes only for local (non-networked) communication.

Bidirectional Pipes

Not all of the shortcomings with pipes are universal. Certain operating systemsfor example, FreeBSD and Solarisimplement bidirectional pipes, wherein the pair of descriptors returned by the pipe system call is such that data written to one can be read on the other. Although the Mac OS X pipe implementation is based on FreeBSD's, Mac OS X 10.4 does not provide bidirectional pipes.

Moreover, it is possible to send a pipe descriptor to another, unrelated process through file descriptor passing, which is supported on Mac OS X. We will see an example of descriptor passing in Section 9.11.


Pipes are also called unnamed pipes , since there also exist named pipes (see Section 9.10). The kernel's internal file descriptor type for a pipe descriptor is DTYPE_PIPE . Descriptors for other IPC mechanisms, such as sockets, POSIX semaphores, and POSIX shared memory, have their own descriptor types. Table 98 shows the various descriptor types used in the kernel.

Table 98. File Descriptor Types Used in the Kernel

Descriptor Type

Notes

DTYPE_VNODE

File

DTYPE_SOCKET

Socket-based communication end point

DTYPE_PSXSHM

POSIX shared memory

DTYPE_PSXSEM

POSIX semaphore

DTYPE_KQUEUE

Kqueue

DTYPE_PIPE

Pipe

DTYPE_FSEVENTS

File system event notification descriptor




9.10. Named Pipes (Fifos)

A named pipealso called a fifo is an abstraction that provides the functionality of an unnamed pipe but uses the file system namespace to represent the pipe, allowing readers and writers to open the fifo file like a regular file. A fifo can be created using the mkfifo() system call or through the mkfifo command-line program.

If a fifo is opened for reading, the open() call will block if there are no writersthat is, if somebody else does not have the fifo open for writing. Conversely, if a fifo is opened for writing, the open() will block if there are no readers. It is possible to open a fifo in nonblocking mode by specifying the O_NONBLOCK flag in the open() call. A nonblocking open for reading will return immediately, with a valid file descriptor, even if there are no writers. A nonblocking open for writing, however, will return immediately with an ENXIO error if there are no readers.

The Mac OS X implementation of fifos internally uses local (Unix Domain) stream socketsthat is, sockets of type SOCK_STREAM in the AF_LOCAL domain.

Although a fifo has physical existence on a file system, it must be different from a regular file for the kernel to treat it as a communication channel with properties that regular files do not have. This is indeed the case: Fifos are conceptually similar to block or character special files in how the file system treats them. Consider a fifo on an HFS Plus volume. The mkfifo() system call simply calls the create operation exported by the HFS Plus file system, additionally setting the type of the vnode as VFIFO . The file type is stored as part of the BSD information structure ( struct HFSPlusBSDInfo ), which in turn is part of the on-disk file metadata. Thereafter, whenever the fifo file is being looked up (typically for opening), the corresponding vnode's file system operations table pointer is switched by HFS Plus to point to another table, some (but not all) of whose operations are that of the fifo file system (fifofs).

Block and character devices on HFS Plus are handled similarly, except the special file system (specfs) is used instead of fifofs. We will see more of fifofs and specfs in Chapter 11. Chapter 12 is entirely dedicated to HFS Plus.


This way, opening a fifo file results in fifo_open() [ bsd/miscfs/fifofs/fifo_vnops.c ] being called. On the first open of a fifo, fifo_open() creates two AF_LOCAL stream sockets: one for reading and the other for writing. Similarly, several other system calls, in particular read() and write() , eventually resolve to fifofs functions.