Beefy Boxes and Bandwidth Generously Provided by pair Networks
Welcome to the Monastery
 
PerlMonks  

How to close all open file descriptors after a fork?

by nneul (Novice)
on Jul 19, 2005 at 13:46 UTC ( [id://476086]=perlquestion: print w/replies, xml ) Need Help??

nneul has asked for the wisdom of the Perl Monks concerning the following question:

I need to be able to fork() in an unknown context where various file handles are likely to be open, including db connections. I've tried the approach of the using the fdopen functionality and closing it for 1..1024 or so, but I didn't figure that would work (and doesn't), since it just opens and closes a new filehandle. The underlying fd still is open afterwards.
#!/usr/bin/perl $| = 1; open(OUT, ">foo"); &CloseAllOpenFiles(); print "done with close.\n"; sleep 20; # go look at process with lsof to see if fd still open sub CloseAllOpenFiles { local *F; for (my $fd=0; $fd<=1024; $fd++) { open F, "<&=$fd" or warn "Cannot reopen fd=$fd: $!"; close F; } }
I saw an approach with pulling in the posix module and using one of it's routines, but I hate to bring in all of POSIX just to close an fd. Is there any reasonable way to do this? Note, I am not planning on issuing an exec(), so the $^F approach won't work.

Replies are listed 'Best First'.
Re: How to close all open file descriptors after a fork?
by jasonk (Parson) on Jul 19, 2005 at 14:04 UTC

    In addition to the method you've tried here, the FAQ also provides documentation on closing a filehandle using the syscall directly.

    # from perlfaq5 require ’sys/syscall.ph’; $rc = syscall(&SYS_close, $fd + 0); # must force numeric die "can’t sysclose $fd: $!" unless $rc == -1;

    The method you tried didn't work for me either (which makes me wonder why it's in the FAQ), but this one did. Here is the test script I used:

    #!/usr/bin/perl -w require 'sys/syscall.ph'; $| = 1; open(OUT, ">foo"); &CloseAllOpenFiles(); print "done with close.\n"; sleep 20; # go look at process with lsof to see if fd still open sub CloseAllOpenFiles { for my $fd (0 .. 1024) { my $rc = syscall(&SYS_close, $fd); warn "Can't sysclose $fd: $!" unless $rc == -1; } }

    We're not surrounded, we're in a target-rich environment!
      Ah, the syscall approach seems a bit less overhead, and seems to work well. Thanks.
Re: How to close all open file descriptors after a fork?
by davidrw (Prior) on Jul 19, 2005 at 14:06 UTC
Re: How to close all open file descriptors after a fork?
by blazar (Canon) on Jul 19, 2005 at 13:55 UTC
    Maybe this is not what you want. But why don't you open all of your FDs as "lexical FHs" (recommended in any case, IMHO) and push them into an @array. You can later close $_ for @ARRAY if needed. (I prefer "lexical FHs" because they will automatically closed on scope exit1 - I'm aware that sockets require an explicit close, though.)

    Update: incidentally

    • The &-form of sub call is now obsolete and most likely not to do what one expects in most situations unless one really knows what he is doing.
    • C-style for loops are legal, but are more error-prone and less reliable, not to say clear, than the corresponding perlish construncts.


    1 Or more precisely when no more references exist.

      I prefer "lexical FHs" because they will automatically closed on scope exit
      No they won't. Your array will still hold a copy and they all will be kept open.

      These file handles are references, are they not? You could try weaken these references in the array, and they'll automatically go away as normal — leaving just an undef in place.

        No they won't. Your array will still hold a copy and they all will be kept open.
        I meant: "in a general situation". In this particular one I suggested to explicitly close the entries kept in the array. I also included a footnote mentioning the ref thing.
        These file handles are references, are they not? You could try weaken these references in the array, and they'll automatically go away as normal — leaving just an undef in place.
        This is a very interesting suggestion, although I have no experience myself weakening references. I won't try because this is not my problem, but I will keep it in mind for when it may be of some use for me...
      The problem is the "unknown context". This is in a subroutine that needs to spawn a background task, called from code that is not under my control. Therefore, I don't know what FDs/FHs are open.
        Well, in that case you may want to choose a way, to "spawn a background task" that will give you the pid of that task, and hopefully if you're under an OS that will let you access the relevant info for that process, you could check that.

        For example under Linux you will be able, and may want to examine "/proc/$pid/fd/".

      I've seen that mentioned before about the & style sub calls, old habits... Got any pointers to more details about that being obsolete?
        Yes, of course I should have mentioned it in my first reply (and I thought I did): perldoc -q perlsub.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://476086]
Approved by Tanalis
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others imbibing at the Monastery: (4)
As of 2024-04-23 16:00 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found