If a process has many file descriptors open, and forks a child
process for some long term purpose, the child needs to close
those file descriptors it is not using. If it does not, those
file descriptors effectively stay open when the parent closes
them for real purposes. For pipes to other child processes,
for example, the pipe will not give an end-of-file. For network
connections, the connection would not get disconnected from the
side of this machine.
Obviously, what needs to happen right after fork(), in the child
process, is to close all file descriptors that the child does not
need to have open. But what file descriptors should be closed?
It might seem that the obvious answer is to keep track of all
that are open, and use that list to close them all. But this
might not always be possible. Many library functions that do
things involving an open file descriptor held open between calls
could keep the fd number hidden. Then the main program cannot
really keep track of all the file descriptors that are open for
the child to close.
Another approach is to simply attempt the close() call on every
possible file descriptor that could exist, skipping the ones the
child actually needs. But to do this correctly, there needs to
be an accurate and portable way to know the whole range. This
also might use a lot of resources, especially if the range is
So I can see a critical issue brewing. I might be tempted toQuote:> One thing to watch out for is really high limits. In the next Solaris
> release, we will have a routine that uses /proc/self/fd to close
> all open fds. This was done because we want to really increase the limit;
> calling close() thousands of times is not going to be efficient.
suggest a new kernel syscall:
close_all_except( ..., -1 );
which would close all file descriptors not listed in the given
list of file descriptors. Another approach might be to create
a "close on fork" concept, but that would only be useful if
that is the default (else you end up having to set the flag
on all those unknown fds). I don't think it would be very
easy to ever get a new syscall like that in place as even if
everyone agreed on it today, it would still be years before
we can even count on it being around in most places. The real
solution will have to be something in the here and now.
I've already seen discussions on how to find the range of all
file descriptors, and can see more than one reason to need to
do this. For example a program I recently wrote will output
a stream of web log data into multitudes of separate files based
on many factors. It has to open many files, and in many cases
the files are written to very often. So it tries to keep the
file descriptors open. It also tries to close them after some
amount of time, and that amount of time diminishes as the number
that are open approaches the maximum number. So it needs to
know the maximum number to do this calculation. As it turns
out, I made this number itself be dynamic, starting at a value
configured in, adjusted very slowly upwards, and adjusted back
down when an open fails for lack of resources (not just out of
file descriptors, but also issues like out of kernel memory).
But at the moment I'm looking at the issue of "left open" file
descriptors in forked child processes, and trying to examine
what would be the best approach to solve it. In particular,
I am wanting to address it in terms of writing not just the
parent/child forking code, but also in terms of writing library
code to do it for the parent/child, or writing library code
that has to open (and maybe hide) file descriptors for other
purposes, as well as for forking purposes (what the library
does for the main program is make a pipe and fork a child
when the programmer shouldn't even need to be aware that the
library even has and open fd).
Suggestions?
Experiences?
Comments?
--
-----------------------------------------------------------------
| Phil Howard - KA9WGN | Dallas | http://linuxhomepage.com/ |
-----------------------------------------------------------------