eleron has asked for the wisdom of the Perl Monks concerning the following question:
|
---|
Replies are listed 'Best First'. | |
---|---|
Re: how to close all files
by almut (Canon) on Oct 23, 2008 at 12:50 UTC | |
Unfortunately, this is a non-trivial problem. The lsof (list open files) utility may help however (if you're on a platform that has it...). Or the Perl wrapper Unix::Lsof, written by a fellow monk. Update: just a few more words on where this can get tricky. Consider the not so untypical scenario of getting a long running forked process to dissociate cleanly in some webserver context, such that the (grand-)parent process may continue normally and serve subsequent requests. For this, it's necessary to close any file handles in the child that the grandparent would otherwise wait for to be closed (and thus block/hang). Now, with a regular CGI program this is still rather simple (by default, closing stdout/stderr is sufficient), but if you, let's say, have a FastCGI environment with persistent DBI/DBD connections to an Oracle database, things can get somewhat more involved. In particular because the respective modules and libraries under the hood may have opened files and sockets on their own, which are not under your immediate control. Also, as practice shows, brute force methods closing all handles may indirectly render the parent process non-functional... That said, as long as your code has full control over which files are being opened, I agree it's usually best to just keep track of what needs to be closed (as has already been suggested elsewhere in the thread). | [reply] [d/l] [select] |
Re: how to close all files
by JavaFan (Canon) on Oct 23, 2008 at 13:25 UTC | |
First, get a list of file descriptors. On many Unix systems, you can use lsof for that, or look in the /proc filesystem (which will have a different format on different OSses). On my system, I can do: Now you have a list of filedescriptors. Unfortunally, you cannot use Perl's close with just the filedescriptor. But don't despair, Perl does give you access to the system calls. syscall is unknown to many people, but it's powerful. On a Unix system, the following ought to work: Frankly, I rather keep track of my filehandles. ;-) | [reply] [d/l] [select] |
by massa (Hermit) on Oct 23, 2008 at 13:46 UTC | |
would work better, as perl closes all files on exec??
[]s, HTH, Massa (κς,πμ,πλ)
| [reply] [d/l] [select] |
by JavaFan (Canon) on Oct 23, 2008 at 14:22 UTC | |
Beginning with v5.6.0, Perl will attempt to flush all files opened for output before forking the child process, but this may not be supported on some platforms (see perlport). To be safe, you may need to set $| ($AUTOFLUSH in English) or call the "autoflush()" method of "IO::Handle" on any open handles in order to avoid duplicate output.Forking cannot easily be replaced with an exec of itself. The process may have done extensive computation for instance. Furthermore, after an exec(), you still have open file handles: STDIN, STDOUT and STDERR. | [reply] |
by Illuminatus (Curate) on Oct 23, 2008 at 15:28 UTC | |
As for what JavaFan suggests, keeping track of open file descriptors when you know you might need to close them all at the same time is painful, but probably the wisest. Simply finding the open descriptors and closing them may or may not be a good idea. Some open descriptors may be within the context of included modules, and simply closing the descriptor without invoking the 'normal' close/disconnect/exit method might not produce the expected/desired results. | [reply] |
by mr_mischief (Monsignor) on Oct 23, 2008 at 23:47 UTC | |
| [reply] |
Re: how to close all files
by Fletch (Bishop) on Oct 23, 2008 at 13:09 UTC | |
There's always the BFI method: start at 0, create a filehandle for that descriptor, close it, increment and repeat until you reach a maximum (there's probably a way to tickle the maximum possible file descriptor number out of POSIX but I can't recall it offhand and my copy of APUE isn't readily available).
Update: Dur, never mind me. The correct mechanism is POSIX::close as is mentioned below, not dup'ing. MENTAL NOTE: NO POSTING BEFORE CAFFEINE . . .
The cake is a lie. | [reply] [d/l] [select] |
by mr_mischief (Monsignor) on Oct 23, 2008 at 23:41 UTC | |
I think there's some misunderstanding of what a duplicate filehandle does. What you have is very nice for closing the duplicates. It doesn't close the originals, though. Duplicate file handles to the same descriptor may share lock status, but they still open and close separately. I did test this with 255 instead of 20 BTW, but you don't really need to see 255 warnings scroll by. There are fewer than 20 files open here, anyway. Just call it the "arbitrarily large" constant people have been tossing out. If you really want to close by descriptor, use POSIX::close as suggested by BrowserUk at Re: how to close all files.
| [reply] [d/l] [select] |
Re: how to close all files
by mr_mischief (Monsignor) on Oct 23, 2008 at 17:14 UTC | |
The sample code assumes you have a subdirectory called "files" in the current directory to keep from polluting your current directory. (I'm planning a Meditations post later about my method of organizing PM tests, examples, benchmarks, and sample data files for them. I'll update this with a ref to that when it's posted). First, we have an array. Notice that the files get successfully closed then one receives warnings about the second print to each.
Now we have a hash, which has multiple descriptive handle names grouped in one handy data structure. It closes then tries to print to the files just as the array example did.
There's nothing special about filehandles after a fork. Closing the files through the filehandles in the parent does not close them in the child. Closing them in the child does not close them in the parent. Closing them in one child does not close them in other children. By keeping the files you open grouped in a convenient container data structure through which you can iterate, you can close them just as easily after a fork as in a single process.
You may note that the parent waits until after the child has exited before it even attempts to write to the files. The child cannot write to them, because it closed its files through the handles. The parent has no problem, because the files are still open in the parent. Grouping filehandles in an array or hash is nothing revolutionary. It can make your life (well, your programming task, anyway) a whole lot easier if you need to treat data as a group to keep it grouped. Filehandles aren't just simple string or numeric data, but they are data. It's not just for forked processes, either. Another example application for this technique is in fact a non-forking server process that will accept an unknown number of connections. Anything that needs to open all the files in a directory and keep them all open at once rather than opening and closing them serially is a good candidate, too. Any program which opens a varying number of files, pipes, or sockets for any reason can benefit. | [reply] [d/l] [select] |
Re: how to close all files
by BrowserUk (Patriarch) on Oct 23, 2008 at 18:06 UTC | |
Start at 0 if you want to close stdin stdout and stderr also.
Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.
| [reply] [d/l] |
by eleron (Novice) on Oct 24, 2008 at 09:40 UTC | |
| [reply] |