Skip to content

pipe · read · write · close

The buffer is 64K, and that is the bug

A pipe holds a finite number of bytes. A writer that fills it blocks, and a reader that is waiting for the writer to exit first will wait forever.

A pipe is not a queue

A pipe holds about sixty-four kilobytes. Writing more than that does not fail and does not grow the buffer — the writer blocks, inside the write, until somebody reads.

This is the mechanism behind the most common way a subprocess call hangs. The parent starts a child with its output on a pipe, waits for it to exit, and then reads. The child fills the buffer, blocks in write, and never exits. The parent waits for a process that is waiting for the parent. Neither moves again.

It works perfectly on small output. Nothing in either program mentions sixty-four thousand anything.

Try this
#include <unistd.h>
#include <sys/wait.h>

int main(void) {
  int fds[2];
  char big[100000];
  pipe(fds);

  pid_t pid = fork();
  if (pid == 0) {
    close(fds[0]);
    write(fds[1], big, 100000);
    _exit(0);
  }

  close(fds[1]);
  int status;
  waitpid(pid, &status, 0);
  return 0;
}

Watch: Both calls left open at the end of the trace, and what the machine says stopped it.

pipes-and-the-deadlock

The ends nobody closes

pipe gives both ends to one process, and after fork both processes have both. That is four descriptors on two ends, and every one of them counts.

A reader sees end-of-file when every writer has closed. If the parent forgot to close its own copy of the write end, there is still a writer — itself — and the read waits forever for a byte that is never coming.

A writer gets EPIPE, and a SIGPIPE that kills it by default, when every reader has closed. That asymmetry is why yes | head -1 terminates instead of running until the disk fills.

Predict

A parent forks a child to write to a pipe, and the parent reads. The parent does not close its own write end. What happens?

pipes-and-the-deadlock

Trace

Run one of the programs on the left.

Everything you do here stays in this browser.Part of liter8.sh