Weird behaviour of Named Pipes

Markus Schoder (markus.schoder@inetmail.de)
Mon, 20 Dec 1999 01:33:57 +0100 (MET)


There is a weirdness with FIFOs (named pipes) and Linux 2.3.33
(probably older kernels too) when doing the following

Terminal 1:

$ mkfifo /tmp/f
$ cat /tmp/f

Terminal 2:

$ echo hello >/tmp/f

I would have expected that the cat does now produce `hello' instead it
just sits there (most of the time). After several echo invocations the
cat will output everything at once and then exit.

I don't have the POSIX specs but this behaviour looks weird.

The reason for this behaviour is a race condition in fifo_open which the
following patch attempts to fix. Note that this race condition is
probably much more likely to trigger on an UP system.

What happens is that between the interruptible_sleep_on call of the reader
(the cat command in the example) an the down for the pipe semaphore, the
writer (the echo command) does write to the pipe and close the pipe. The
reader then checks the writer count, finds it to be zero and continues to
sleep.

The patch changes this bevaviour so that the reader successfully completes
the open even if no writer is present anymore relying on the fact that a
writer must have been present for the wakeup of the reader to occur.

(Please reply by email since I currently don't have access to the mailing
list).

--
Markus

--- fifo.c.old Mon Dec 20 00:36:33 1999 +++ fifo.c Mon Dec 20 00:38:39 1999 @@ -55,17 +55,13 @@ wake_up_interruptible(PIPE_WAIT(*inode)); if (!(filp->f_flags & O_NONBLOCK)) { - while (!PIPE_WRITERS(*inode)) { + if (!PIPE_WRITERS(*inode)) { if (signal_pending(current)) goto err_rd; + filp->f_op = &read_fifo_fops; up(PIPE_SEM(*inode)); interruptible_sleep_on(PIPE_WAIT(*inode)); - - /* Note that using down_interruptible here - and similar places below is pointless, - since we have to acquire the lock to clean - up properly. */ - down(PIPE_SEM(*inode)); + return 0; } } @@ -87,12 +83,12 @@ if (!PIPE_WRITERS(*inode)++) wake_up_interruptible(PIPE_WAIT(*inode)); - while (!PIPE_READERS(*inode)) { + if (!PIPE_READERS(*inode)) { if (signal_pending(current)) goto err_wr; up(PIPE_SEM(*inode)); interruptible_sleep_on(PIPE_WAIT(*inode)); - down(PIPE_SEM(*inode)); + return 0; } break;

- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.rutgers.edu Please read the FAQ at http://www.tux.org/lkml/