File descriptor ownership and lifetimes
Lassi Kortela 09 May 2019 12:00 UTC
From the first draft:
> Ports are garbage-collected Scheme objects, not integers. When a port
is garbage collected, it is also closed. Because file descriptors are
just integers, it's impossible to garbage collect them — you wouldn't be
able to close file descriptor 3 unless there were no 3's in the system.
> Suppose we have a Scheme port constructed on top of file descriptor
3. We intend to fork off a program that will inherit this file
descriptor. If we drop references to the port, the garbage collector may
prematurely close file 3 before we fork the subprocess.
> Unfortunately, there is no even vaguely portable solution to this
problem. Scsh and Guile undertake heroic measures to open new file
descriptors for ports when the old file descriptors are repurposed for
something else, and to track when closing a port implies closing its
file descriptor or not. But doing so involves more changes than an
implementation should have to make in order to provide this SRFI.
Remarks:
- In one way, it's even more difficult than this. Several file
descriptors (even in different processes!) can refer to the same "ofile"
(a file handle in the kernel). This notoriously affects things like the
flag that sets whether reads are blocking or non-blocking.
- It would appear to me that the concept of a Scheme port that does
_not_ close the underlying file descriptor when it's GC'd is absolutely
necessary for a sane OS API.
- I would leave it up to users to ensure that they use the right mix of
fd-closing and non-fd-closing ports for their application. It seems
almost impossible to anticipate all use cases if the Scheme
implementation tries to keep tally of all open ports to particular fd's.
Even if it's possible, it's probably complex and extremely subtle so it
would the abstraction would leak. But I haven't thought in detail about
this problem. It would be good to hear more from the people who
implemented this stuff in Scsh and Guile.
- I would just live with the fact that Scheme ports and fd's are two
different "namespaces" (or object spaces) that do not inform each other
when one of them changes. I would leave it all up to the application
programmer (who will be the one writing the code to make the relevant
changes anyway).