Skip Menu |

This queue is for tickets about the IO-Async CPAN distribution.

Report information
The Basics
Id: 97942
Status: resolved
Priority: 0/
Queue: IO-Async

People
Owner: Nobody in particular
Requestors: TEAM [...] cpan.org
Cc:
AdminCc:

Bug Information
Severity: Wishlist
Broken in: (no value)
Fixed in: 0.64



Subject: More efficient close()-on-fork
As discussed... The close()-on-fork behaviour slows down a bit when max FD is high, for example running under ulimit -n 1000000 Making this OS-specific and using the /proc/$$/fd interface on Linux helps performance there noticeably, other platforms might have similar facilities (or at least the ability to report max actual used FD). Patch attached for moving this to a method on IO::Async::OS and a basic ::linux implementation, unfortunately it includes the /proc/$$/fd dir handle since I couldn't see a way to exclude this fileno from the list (fileno($dir) returns undef). Does this need a platform-specific test? Maybe override CORE::close and check that it's not being called too often? cheers, Tom
Subject: 2014-08-11-linux-fd-close.patch
=== modified file 'lib/IO/Async/ChildManager.pm' --- lib/IO/Async/ChildManager.pm 2014-07-11 14:16:53 +0000 +++ lib/IO/Async/ChildManager.pm 2014-08-11 19:22:19 +0000 @@ -604,7 +604,7 @@ } } - foreach ( 0 .. OPEN_MAX_FD ) { + foreach ( IO::Async::OS->potentially_open_fds ) { next if $fds_refcount{$_}; next if $_ == fileno $writepipe; POSIX::close( $_ ); === modified file 'lib/IO/Async/OS.pm' --- lib/IO/Async/OS.pm 2014-07-11 14:16:53 +0000 +++ lib/IO/Async/OS.pm 2014-08-11 18:57:26 +0000 @@ -30,6 +30,9 @@ use IO::Socket (); # empty import +use POSIX qw( sysconf _SC_OPEN_MAX ); +use constant OPEN_MAX_FD => eval { sysconf(_SC_OPEN_MAX) } || 1024; + # Some constants that define features of the OS use constant HAVE_SOCKADDR_IN6 => defined eval { pack_sockaddr_in6 0, inet_pton( AF_INET6, "2001::1" ) }; @@ -565,6 +568,19 @@ undef $SIG{$signal}; } +=head2 my @fds = IO::Async::OS->potentially_open_fds + +Returns a list of filedescriptors which might need +closing. By default this will return _SC_OPEN_MAX, +OS-specific subclasses may have a better guess. + +=cut + +sub potentially_open_fds +{ + 0 .. OPEN_MAX_FD; +} + =head1 AUTHOR Paul Evans <leonerd@leonerd.org.uk> === added file 'lib/IO/Async/OS/linux.pm' --- lib/IO/Async/OS/linux.pm 1970-01-01 00:00:00 +0000 +++ lib/IO/Async/OS/linux.pm 2014-08-11 19:23:54 +0000 @@ -0,0 +1,55 @@ +# You may distribute under the terms of either the GNU General Public License +# or the Artistic License (the same terms as Perl itself) +# +# (C) Paul Evans, 2014 -- leonerd@leonerd.org.uk + +package IO::Async::OS::linux; + +use strict; +use warnings; + +our $VERSION = '0.63'; + +our @ISA = qw( IO::Async::OS::_Base ); + +=head1 NAME + +C<IO::Async::OS::linux> - operating system abstractions on C<Linux> for C<IO::Async> + +=head1 DESCRIPTION + +This module contains OS support code for C<Linux>. + +See instead L<IO::Async::OS>. + +=cut + +# Try to use /proc/pid/fd to get the list of +# actually-open file descriptors for our +# process. Saves a bit of time when running with +# high ulimit -n / fileno counts. +sub potentially_open_fds +{ + my $class = shift; + opendir my $fd_path, "/proc/$$/fd" or do { + warn "Cannot open /proc/$$/fd, falling back to generic method - $!"; + return $class->SUPER::potentially_open_fds + }; + + # Skip ., .., our directory handle itself and any other cruft + # except fileno() isn't available for the handle so we'll + # end up with that in the output anyway. As long as we're + # called just before the relevant close() loop, this + # should be harmless enough. + my @fd = map /^([0-9]+)$/ ? $1 : (), readdir $fd_path; + closedir $fd_path; + return @fd; +} + +=head1 AUTHOR + +Paul Evans <leonerd@leonerd.org.uk> + +=cut + +0x55AA;
On Mon Aug 11 15:29:51 2014, TEAM wrote: Show quoted text
> Patch attached for moving this to a method on IO::Async::OS and a > basic ::linux implementation, unfortunately it includes the > /proc/$$/fd dir handle since I couldn't see a way to exclude this > fileno from the list (fileno($dir) returns undef).
Applied, with some minor formatting fixes. Show quoted text
> Does this need a platform-specific test? Maybe override CORE::close > and check that it's not being called too often?
I'm not sure a test is strictly necessary. The function is quite small and easy to confirm casually: $ perl -Mblib -MIO::Async::OS -E 'say for IO::Async::OS->potentially_open_fds' 0 1 2 3 Trying to automate a test for this that asserts it definitely doesn't list an FD it shouldn't is likely to require more code than the implementation takes anyway. -- Paul Evans
Released -- Paul Evans