USP: An introduction to the Unix pipe
2011-09-23 00:35, written by Eric WongThe Unix pipe is the first example of an anonymous file we will cover.
Unlike regular files and directories, anonymous files do not exist on the filesystem and do not persist across reboots. Only the process that creates the anonymous file (and its descendants) can access anonymous files. Anonymous files only persist until the last process using it closes it.
At its heart, the Unix pipe is just like a pipe in plumbing, a one-way buffer for transporting payload from one end to another.
It is implemented as a circular ring buffer in the kernel:
user space | kernel space
-----------------------------------------------
|
data in --> fd[writer] ->- file[writer] -->\
| \
| [buffer]
| /
data out <-- fd[reader] -<- file[reader] <--/
|
The buffer is created by the pipe(2) system call and persists until both files are closed. In Ruby, the IO.pipe method calls pipe(2) and returns an array of two Ruby IO objects, a reader and writer:
reader, writer = IO.pipe # kernel creates internal buffer
Writing can be accomplished by making the write(2) syscall, the writer IO object should default to IO#sync=true at creation.
writer.write("HELLO")
Reading can be accomplished by making the read(2) syscall.
reader.read(5) # => "HELLO"
Finally, the kernel memory for the buffer is released after both file objects (through file descriptors and IO) are closed:
writer.close
reader.close
# Kernel frees the buffer
As with regular files, pipes operate on byte streams and leaves higher-level functionality (like encoding) to user space.
Pipes also have important atomicity requirements standardized by POSIX. Given the importance of pipes in Unix programming, we will revisit and give pipes much more coverage in the future.
License: GPLv3 (or later, at the discretion of Eric Wong)