perlio 'unix' layer file descriptor handling

Do you have a question? Post it now! No Registration Necessary.  Now with pictures!

Something (AFAIK) undocumented which bit me recently[*]: The perlio
'unix' layer maintains reference counts for all file descriptors used
by 'Perl STREAMS' (yes, I mean STREAMS) and in particular, a close
call performed on such a stream will only result in the file
descriptor being closed when the reference count drops to zero because
of that. This implies that 'nasty things' will happen when perl gets
access to file descriptors managed by independent code and that

open($fh, '<&=', $fd);

should only be used of the file descriptor will henceforth be 'owned'
by perl.

[*] The particular problem situation was that a perl stream was
creating using such an open call and the descriptor returned by the
DBD::Pg 'getfd' implementation specific interface. This was done so
that the asynchronous interface of libpq could be used together with
'a file descriptor based I/O multiplexing loop'. The (heavily
customized) database driver used here would invoke PQFinish on the
'internal' connection object when an attempt to establish a connection
asynchronously failed, closing the file descriptor as side
effect. Since this didn't destroy the 'perl stream' it remained in the
unix layer file descriptor table with a reference count of one. In
certain situations, the code would create a pipe using POSIX::pipe and
turn the write end of that into a perl stream with another 'fdopen'
open before the 'perl database streams' was destroyed. This pipe call
would return the descriptor number formerly used by the database
connection and the perl-internal reference count would thus become 2
after the 'pipe writing' stream was opened. This pipe stream was used
to write 'some commands' to an auxiliary program which would wait
until an EOF on its standard input before performing any actual
work. Because of the botched reference count, the 'close' call on the
pipe stream would not close the file descriptor and the end-result
would be the helper process waiting for the EOF and perl waiting (via
wait) for the helper process to terminate.

Site Timeline