I can reproduce what you're seeing on Ubuntu:
#!/bin/bash -eu
rm -rf named_pipe
mkfifo named_pipe
echo 12 > named_pipe
$ ./namedpipe.sh & # background it
$ php named_pipe # same terminal; don't need another window
2
It's something with php
. I could not reproduce it with cat
(which would show that the fifo code in the kernel is seriously broken).
An strace
log over php
shows that it has read the data from the pipe: two digits and a newline:
open("named_pipe", O_RDONLY|O_LARGEFILE) = 3
fstat64(3, {st_mode=S_IFIFO|0664, st_size=0, ...}) = 0
mmap2(NULL, 65536, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb6fdc000
read(3, "12\n", 65536) = 3
The next thing it tries of file descriptor 3
is an lseek:
_llseek(3, 0, 0xbf93c640, SEEK_SET) = -1 ESPIPE (Illegal seek)
This is where things may be going wrong. Suppose that this is called through some buffered I/O library which gets confused by pipes and messes up its buffer.
At this point, numerous other operations take place.
Later it tries a few more operations, including an attempt to get tty settings and one more read which clearly indicates EOF:
ioctl(3, SNDCTL_TMR_TIMEBASE or TCGETS, 0xbf93a2e8) = -1 EINVAL (Invalid argument)
fstat64(3, {st_mode=S_IFIFO|0664, st_size=0, ...}) = 0
read(3, "", 65536) = 0
PHP doesn't believe that a zero return on a blocking read of a Unix pipe means EOF and so it tries again:
read(3, "", 65536) = 0
close(3)
The very next two lines in the trace are these. The very buffer that was allocated prior to that read is released (perhaps the stream buffer?) Followed by the chopped output:
munmap(0xb6fdc000, 65536) = 0
write(1, "2\n", 2) = 2
So that pretty much answers the question of what software is responsible. If you want to dig into it more, a way forward would be to get a debug build of php
and step into it with gdb
.
Addendum:
The behavior is quite different when php
reads from standard input, like in the echo 12 | php
case. For example, the llseek
operation is never tried on file descriptor 0. Also, the stream is never closed (of course) and there are no intervening operations between the read and write. The following appears as a contiguous block:
read(0, "12\n", 4096) = 3
read(0, "", 4096) = 0
read(0, "", 4096) = 0
write(1, "12\n", 3) = 3
One would expect that opening a file named on the command line goes through different flow compared to reading from standard input (probably represented by some specially set up global standard input stream object).
$php <(echo 45)
gives me 5 whereas$cat <(echo 45)
gives me 45.echo 45 | php
outputs 45.