diff options
author | gregor herrmann <gregoa@debian.org> | 2021-11-12 16:59:19 +0100 |
---|---|---|
committer | gregor herrmann <gregoa@debian.org> | 2021-11-12 16:59:19 +0100 |
commit | ac10c25ce4711d5ff3cab3f6b61a5125ed9c2d02 (patch) | |
tree | ab8a4ce9c09fc69b351edb122d0dd65a8e7861e2 | |
parent | 1af6c7552de129a387862c97c51ed6754a76fdc6 (diff) |
New upstream version 0.800
46 files changed, 302 insertions, 229 deletions
@@ -27,6 +27,7 @@ my $build = Module::Build->new( test_requires => { 'File::Temp' => 0, 'Test::Fatal' => 0, + 'Test::Future::IO::Impl' => 0, 'Test::Identity' => 0, 'Test::Metrics::Any' => 0, 'Test::More' => '0.88', @@ -1,5 +1,15 @@ Revision history for IO-Async +0.800 2021-11-11 + [CHANGES] + * Bumped up to three-digit minor version number + * Added IO::Async::OS->signum2name + * Implement Future::IO->waitpid API + * Skip the `spawn` Routine model if POSIX fork() is not available + * Replace getaddrinfo / getnameinfo with virtual mocking functions + for unit-testing the resolve, so as not to rely on local platform + resolver behaviours + 0.79 2021-08-06 [CHANGES] * Permit IO::Async::Routine or Function by module+func names instead @@ -41,6 +41,7 @@ "requires" : { "File::Temp" : "0", "Test::Fatal" : "0", + "Test::Future::IO::Impl" : "0", "Test::Identity" : "0", "Test::Metrics::Any" : "0", "Test::More" : "0.88", @@ -54,146 +55,146 @@ }, "IO::Async" : { "file" : "lib/IO/Async.pm", - "version" : "0.79" + "version" : "0.800" }, "IO::Async::Channel" : { "file" : "lib/IO/Async/Channel.pm", - "version" : "0.79" + "version" : "0.800" }, "IO::Async::Debug" : { "file" : "lib/IO/Async/Debug.pm", - "version" : "0.79" + "version" : "0.800" }, "IO::Async::File" : { "file" : "lib/IO/Async/File.pm", - "version" : "0.79" + "version" : "0.800" }, "IO::Async::FileStream" : { "file" : "lib/IO/Async/FileStream.pm", - "version" : "0.79" + "version" : "0.800" }, "IO::Async::Function" : { "file" : "lib/IO/Async/Function.pm", - "version" : "0.79" + "version" : "0.800" }, "IO::Async::Future" : { "file" : "lib/IO/Async/Future.pm", - "version" : "0.79" + "version" : "0.800" }, "IO::Async::Handle" : { "file" : "lib/IO/Async/Handle.pm", - "version" : "0.79" + "version" : "0.800" }, "IO::Async::Internals::ChildManager" : { "file" : "lib/IO/Async/Internals/ChildManager.pm", - "version" : "0.79" + "version" : "0.800" }, "IO::Async::Internals::FunctionWorker" : { "file" : "lib/IO/Async/Internals/FunctionWorker.pm", - "version" : "0.79" + "version" : "0.800" }, "IO::Async::Listener" : { "file" : "lib/IO/Async/Listener.pm", - "version" : "0.79" + "version" : "0.800" }, "IO::Async::Loop" : { "file" : "lib/IO/Async/Loop.pm", - "version" : "0.79" + "version" : "0.800" }, "IO::Async::Loop::Poll" : { "file" : "lib/IO/Async/Loop/Poll.pm", - "version" : "0.79" + "version" : "0.800" }, "IO::Async::Loop::Select" : { "file" : "lib/IO/Async/Loop/Select.pm", - "version" : "0.79" + "version" : "0.800" }, "IO::Async::LoopTests" : { "file" : "lib/IO/Async/LoopTests.pm", - "version" : "0.79" + "version" : "0.800" }, "IO::Async::Metrics" : { "file" : "lib/IO/Async/Metrics.pm" }, "IO::Async::Notifier" : { "file" : "lib/IO/Async/Notifier.pm", - "version" : "0.79" + "version" : "0.800" }, "IO::Async::OS" : { "file" : "lib/IO/Async/OS.pm", - "version" : "0.79" + "version" : "0.800" }, "IO::Async::OS::MSWin32" : { "file" : "lib/IO/Async/OS/MSWin32.pm", - "version" : "0.79" + "version" : "0.800" }, "IO::Async::OS::cygwin" : { "file" : "lib/IO/Async/OS/cygwin.pm", - "version" : "0.79" + "version" : "0.800" }, "IO::Async::OS::linux" : { "file" : "lib/IO/Async/OS/linux.pm", - "version" : "0.79" + "version" : "0.800" }, "IO::Async::PID" : { "file" : "lib/IO/Async/PID.pm", - "version" : "0.79" + "version" : "0.800" }, "IO::Async::Process" : { "file" : "lib/IO/Async/Process.pm", - "version" : "0.79" + "version" : "0.800" }, "IO::Async::Protocol" : { "file" : "lib/IO/Async/Protocol.pm", - "version" : "0.79" + "version" : "0.800" }, "IO::Async::Protocol::LineStream" : { "file" : "lib/IO/Async/Protocol/LineStream.pm", - "version" : "0.79" + "version" : "0.800" }, "IO::Async::Protocol::Stream" : { "file" : "lib/IO/Async/Protocol/Stream.pm", - "version" : "0.79" + "version" : "0.800" }, "IO::Async::Resolver" : { "file" : "lib/IO/Async/Resolver.pm", - "version" : "0.79" + "version" : "0.800" }, "IO::Async::Routine" : { "file" : "lib/IO/Async/Routine.pm", - "version" : "0.79" + "version" : "0.800" }, "IO::Async::Signal" : { "file" : "lib/IO/Async/Signal.pm", - "version" : "0.79" + "version" : "0.800" }, "IO::Async::Socket" : { "file" : "lib/IO/Async/Socket.pm", - "version" : "0.79" + "version" : "0.800" }, "IO::Async::Stream" : { "file" : "lib/IO/Async/Stream.pm", - "version" : "0.79" + "version" : "0.800" }, "IO::Async::Test" : { "file" : "lib/IO/Async/Test.pm", - "version" : "0.79" + "version" : "0.800" }, "IO::Async::Timer" : { "file" : "lib/IO/Async/Timer.pm", - "version" : "0.79" + "version" : "0.800" }, "IO::Async::Timer::Absolute" : { "file" : "lib/IO/Async/Timer/Absolute.pm", - "version" : "0.79" + "version" : "0.800" }, "IO::Async::Timer::Countdown" : { "file" : "lib/IO/Async/Timer/Countdown.pm", - "version" : "0.79" + "version" : "0.800" }, "IO::Async::Timer::Periodic" : { "file" : "lib/IO/Async/Timer/Periodic.pm", - "version" : "0.79" + "version" : "0.800" } }, "release_status" : "stable", @@ -203,6 +204,6 @@ ], "x_IRC" : "irc://irc.perl.org/#io-async" }, - "version" : "0.79", + "version" : "0.800", "x_serialization_backend" : "JSON::PP version 4.05" } @@ -5,6 +5,7 @@ author: build_requires: File::Temp: '0' Test::Fatal: '0' + Test::Future::IO::Impl: '0' Test::Identity: '0' Test::Metrics::Any: '0' Test::More: '0.88' @@ -23,111 +24,111 @@ provides: file: lib/Future/IO/Impl/IOAsync.pm IO::Async: file: lib/IO/Async.pm - version: '0.79' + version: '0.800' IO::Async::Channel: file: lib/IO/Async/Channel.pm - version: '0.79' + version: '0.800' IO::Async::Debug: file: lib/IO/Async/Debug.pm - version: '0.79' + version: '0.800' IO::Async::File: file: lib/IO/Async/File.pm - version: '0.79' + version: '0.800' IO::Async::FileStream: file: lib/IO/Async/FileStream.pm - version: '0.79' + version: '0.800' IO::Async::Function: file: lib/IO/Async/Function.pm - version: '0.79' + version: '0.800' IO::Async::Future: file: lib/IO/Async/Future.pm - version: '0.79' + version: '0.800' IO::Async::Handle: file: lib/IO/Async/Handle.pm - version: '0.79' + version: '0.800' IO::Async::Internals::ChildManager: file: lib/IO/Async/Internals/ChildManager.pm - version: '0.79' + version: '0.800' IO::Async::Internals::FunctionWorker: file: lib/IO/Async/Internals/FunctionWorker.pm - version: '0.79' + version: '0.800' IO::Async::Listener: file: lib/IO/Async/Listener.pm - version: '0.79' + version: '0.800' IO::Async::Loop: file: lib/IO/Async/Loop.pm - version: '0.79' + version: '0.800' IO::Async::Loop::Poll: file: lib/IO/Async/Loop/Poll.pm - version: '0.79' + version: '0.800' IO::Async::Loop::Select: file: lib/IO/Async/Loop/Select.pm - version: '0.79' + version: '0.800' IO::Async::LoopTests: file: lib/IO/Async/LoopTests.pm - version: '0.79' + version: '0.800' IO::Async::Metrics: file: lib/IO/Async/Metrics.pm IO::Async::Notifier: file: lib/IO/Async/Notifier.pm - version: '0.79' + version: '0.800' IO::Async::OS: file: lib/IO/Async/OS.pm - version: '0.79' + version: '0.800' IO::Async::OS::MSWin32: file: lib/IO/Async/OS/MSWin32.pm - version: '0.79' + version: '0.800' IO::Async::OS::cygwin: file: lib/IO/Async/OS/cygwin.pm - version: '0.79' + version: '0.800' IO::Async::OS::linux: file: lib/IO/Async/OS/linux.pm - version: '0.79' + version: '0.800' IO::Async::PID: file: lib/IO/Async/PID.pm - version: '0.79' + version: '0.800' IO::Async::Process: file: lib/IO/Async/Process.pm - version: '0.79' + version: '0.800' IO::Async::Protocol: file: lib/IO/Async/Protocol.pm - version: '0.79' + version: '0.800' IO::Async::Protocol::LineStream: file: lib/IO/Async/Protocol/LineStream.pm - version: '0.79' + version: '0.800' IO::Async::Protocol::Stream: file: lib/IO/Async/Protocol/Stream.pm - version: '0.79' + version: '0.800' IO::Async::Resolver: file: lib/IO/Async/Resolver.pm - version: '0.79' + version: '0.800' IO::Async::Routine: file: lib/IO/Async/Routine.pm - version: '0.79' + version: '0.800' IO::Async::Signal: file: lib/IO/Async/Signal.pm - version: '0.79' + version: '0.800' IO::Async::Socket: file: lib/IO/Async/Socket.pm - version: '0.79' + version: '0.800' IO::Async::Stream: file: lib/IO/Async/Stream.pm - version: '0.79' + version: '0.800' IO::Async::Test: file: lib/IO/Async/Test.pm - version: '0.79' + version: '0.800' IO::Async::Timer: file: lib/IO/Async/Timer.pm - version: '0.79' + version: '0.800' IO::Async::Timer::Absolute: file: lib/IO/Async/Timer/Absolute.pm - version: '0.79' + version: '0.800' IO::Async::Timer::Countdown: file: lib/IO/Async/Timer/Countdown.pm - version: '0.79' + version: '0.800' IO::Async::Timer::Periodic: file: lib/IO/Async/Timer/Periodic.pm - version: '0.79' + version: '0.800' recommends: IO::Socket::IP: '0' requires: @@ -145,5 +146,5 @@ requires: resources: IRC: irc://irc.perl.org/#io-async license: http://dev.perl.org/licenses/ -version: '0.79' +version: '0.800' x_serialization_backend: 'CPAN::Meta::YAML version 0.018' diff --git a/lib/Future/IO/Impl/IOAsync.pm b/lib/Future/IO/Impl/IOAsync.pm index 4d1c0de..469fe35 100644 --- a/lib/Future/IO/Impl/IOAsync.pm +++ b/lib/Future/IO/Impl/IOAsync.pm @@ -1,7 +1,7 @@ # 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, 2019 -- leonerd@leonerd.org.uk +# (C) Paul Evans, 2019-2021 -- leonerd@leonerd.org.uk package Future::IO::Impl::IOAsync; @@ -116,6 +116,22 @@ sub ready_for_write return $f; } +sub waitpid +{ + shift; + my ( $pid ) = @_; + + my $f = ( $loop //= IO::Async::Loop->new )->new_future; + + $loop->watch_process( $pid, sub { + my ( undef, $wstatus ) = @_; + $f->done( $wstatus ); + } ); + $f->on_cancel( sub { $loop->unwatch_process( $pid ) } ); + + return $f; +} + =head1 AUTHOR Paul Evans <leonerd@leonerd.org.uk> diff --git a/lib/IO/Async.pm b/lib/IO/Async.pm index f142456..6cdec40 100644 --- a/lib/IO/Async.pm +++ b/lib/IO/Async.pm @@ -12,7 +12,7 @@ use warnings; # It is provided simply to keep CPAN happy: # cpan -i IO::Async -our $VERSION = '0.79'; +our $VERSION = '0.800'; =head1 NAME diff --git a/lib/IO/Async/Channel.pm b/lib/IO/Async/Channel.pm index 06bfec4..bf8b00a 100644 --- a/lib/IO/Async/Channel.pm +++ b/lib/IO/Async/Channel.pm @@ -9,7 +9,7 @@ use strict; use warnings; use base qw( IO::Async::Notifier ); -our $VERSION = '0.79'; +our $VERSION = '0.800'; use Carp; diff --git a/lib/IO/Async/Debug.pm b/lib/IO/Async/Debug.pm index 8fd4fdc..5da74b8 100644 --- a/lib/IO/Async/Debug.pm +++ b/lib/IO/Async/Debug.pm @@ -8,7 +8,7 @@ package IO::Async::Debug; use strict; use warnings; -our $VERSION = '0.79'; +our $VERSION = '0.800'; our $DEBUG = $ENV{IO_ASYNC_DEBUG} || 0; our $DEBUG_FD = $ENV{IO_ASYNC_DEBUG_FD}; diff --git a/lib/IO/Async/File.pm b/lib/IO/Async/File.pm index 6d7eeaa..26e0d68 100644 --- a/lib/IO/Async/File.pm +++ b/lib/IO/Async/File.pm @@ -8,7 +8,7 @@ package IO::Async::File; use strict; use warnings; -our $VERSION = '0.79'; +our $VERSION = '0.800'; use base qw( IO::Async::Timer::Periodic ); diff --git a/lib/IO/Async/FileStream.pm b/lib/IO/Async/FileStream.pm index 432ca79..c6b3d3f 100644 --- a/lib/IO/Async/FileStream.pm +++ b/lib/IO/Async/FileStream.pm @@ -8,7 +8,7 @@ package IO::Async::FileStream; use strict; use warnings; -our $VERSION = '0.79'; +our $VERSION = '0.800'; use base qw( IO::Async::Stream ); diff --git a/lib/IO/Async/Function.pm b/lib/IO/Async/Function.pm index 3c83a78..d8ca33e 100644 --- a/lib/IO/Async/Function.pm +++ b/lib/IO/Async/Function.pm @@ -8,7 +8,7 @@ package IO::Async::Function; use strict; use warnings; -our $VERSION = '0.79'; +our $VERSION = '0.800'; use base qw( IO::Async::Notifier ); use IO::Async::Timer::Countdown; @@ -125,6 +125,8 @@ body itself. =head2 func => STRING +I<Since version 0.79.> + An alternative to the C<code> argument, which names a module to load and a function to call within it. C<module> should give a perl module name (i.e. C<Some::Name>, not a filename like F<Some/Name.pm>), and C<func> should give diff --git a/lib/IO/Async/Future.pm b/lib/IO/Async/Future.pm index 4cdc3e1..0d9a244 100644 --- a/lib/IO/Async/Future.pm +++ b/lib/IO/Async/Future.pm @@ -8,7 +8,7 @@ package IO::Async::Future; use strict; use warnings; -our $VERSION = '0.79'; +our $VERSION = '0.800'; use base qw( Future ); Future->VERSION( '0.05' ); # to respect subclassing diff --git a/lib/IO/Async/Handle.pm b/lib/IO/Async/Handle.pm index 96eeea0..57b47d0 100644 --- a/lib/IO/Async/Handle.pm +++ b/lib/IO/Async/Handle.pm @@ -9,7 +9,7 @@ use strict; use warnings; use base qw( IO::Async::Notifier ); -our $VERSION = '0.79'; +our $VERSION = '0.800'; use Carp; diff --git a/lib/IO/Async/Internals/ChildManager.pm b/lib/IO/Async/Internals/ChildManager.pm index 3a383e1..fe14451 100644 --- a/lib/IO/Async/Internals/ChildManager.pm +++ b/lib/IO/Async/Internals/ChildManager.pm @@ -8,7 +8,7 @@ package IO::Async::Internals::ChildManager; use strict; use warnings; -our $VERSION = '0.79'; +our $VERSION = '0.800'; # Not a notifier diff --git a/lib/IO/Async/Internals/Connector.pm b/lib/IO/Async/Internals/Connector.pm index 7b54b09..1bb7d48 100644 --- a/lib/IO/Async/Internals/Connector.pm +++ b/lib/IO/Async/Internals/Connector.pm @@ -9,7 +9,7 @@ package # hide from CPAN use strict; use warnings; -our $VERSION = '0.79'; +our $VERSION = '0.800'; use Scalar::Util qw( weaken blessed ); diff --git a/lib/IO/Async/Internals/FunctionWorker.pm b/lib/IO/Async/Internals/FunctionWorker.pm index 4c4665d..42de16f 100644 --- a/lib/IO/Async/Internals/FunctionWorker.pm +++ b/lib/IO/Async/Internals/FunctionWorker.pm @@ -8,7 +8,7 @@ package IO::Async::Internals::FunctionWorker; use strict; use warnings; -our $VERSION = '0.79'; +our $VERSION = '0.800'; # Called directly by IO::Async::Function::Worker when used in "code" mode, # or by run_worker() below. diff --git a/lib/IO/Async/Listener.pm b/lib/IO/Async/Listener.pm index 5fefe49..7ba585c 100644 --- a/lib/IO/Async/Listener.pm +++ b/lib/IO/Async/Listener.pm @@ -9,7 +9,7 @@ use strict; use warnings; use base qw( IO::Async::Handle ); -our $VERSION = '0.79'; +our $VERSION = '0.800'; use IO::Async::Handle; use IO::Async::OS; diff --git a/lib/IO/Async/Loop.pm b/lib/IO/Async/Loop.pm index e81baa6..25d10fe 100644 --- a/lib/IO/Async/Loop.pm +++ b/lib/IO/Async/Loop.pm @@ -8,7 +8,7 @@ package IO::Async::Loop; use strict; use warnings; -our $VERSION = '0.79'; +our $VERSION = '0.800'; # When editing this value don't forget to update the docs below use constant NEED_API_VERSION => '0.33'; diff --git a/lib/IO/Async/Loop/Poll.pm b/lib/IO/Async/Loop/Poll.pm index c5048aa..fe14fd5 100644 --- a/lib/IO/Async/Loop/Poll.pm +++ b/lib/IO/Async/Loop/Poll.pm @@ -8,7 +8,7 @@ package IO::Async::Loop::Poll; use strict; use warnings; -our $VERSION = '0.79'; +our $VERSION = '0.800'; use constant API_VERSION => '0.49'; use base qw( IO::Async::Loop ); diff --git a/lib/IO/Async/Loop/Select.pm b/lib/IO/Async/Loop/Select.pm index 2c52fc6..cce82db 100644 --- a/lib/IO/Async/Loop/Select.pm +++ b/lib/IO/Async/Loop/Select.pm @@ -8,7 +8,7 @@ package IO::Async::Loop::Select; use strict; use warnings; -our $VERSION = '0.79'; +our $VERSION = '0.800'; use constant API_VERSION => '0.49'; use base qw( IO::Async::Loop ); diff --git a/lib/IO/Async/LoopTests.pm b/lib/IO/Async/LoopTests.pm index 70f1a48..3219879 100644 --- a/lib/IO/Async/LoopTests.pm +++ b/lib/IO/Async/LoopTests.pm @@ -28,7 +28,7 @@ use POSIX qw( SIGTERM ); use Socket qw( sockaddr_family AF_UNIX ); use Time::HiRes qw( time ); -our $VERSION = '0.79'; +our $VERSION = '0.800'; # Abstract Units of Time use constant AUT => $ENV{TEST_QUICK_TIMERS} ? 0.1 : 1; diff --git a/lib/IO/Async/Notifier.pm b/lib/IO/Async/Notifier.pm index 46f929e..f1e13ff 100644 --- a/lib/IO/Async/Notifier.pm +++ b/lib/IO/Async/Notifier.pm @@ -8,7 +8,7 @@ package IO::Async::Notifier; use strict; use warnings; -our $VERSION = '0.79'; +our $VERSION = '0.800'; use Carp; use Scalar::Util qw( weaken ); diff --git a/lib/IO/Async/OS.pm b/lib/IO/Async/OS.pm index 7867248..e702aae 100644 --- a/lib/IO/Async/OS.pm +++ b/lib/IO/Async/OS.pm @@ -8,7 +8,7 @@ package IO::Async::OS; use strict; use warnings; -our $VERSION = '0.79'; +our $VERSION = '0.800'; our @ISA = qw( IO::Async::OS::_Base ); @@ -344,25 +344,32 @@ This utility method converts a signal name (such as "TERM") into its system- specific signal number. This may be useful to pass to C<POSIX::SigSet> or use in other places which use numbers instead of symbolic names. +=head2 signum2name + + $signame = IO::Async::OS->signum2name( $signum ) + +The inverse of L<signame2num>; this method convers signal numbers into +readable names. + =cut -my %sig_num; +my %sig_name2num; +my %sig_num2name; + sub _init_signum { my $self = shift; - # Copypasta from Config.pm's documentation - our %Config; require Config; - Config->import; - unless($Config{sig_name} && $Config{sig_num}) { + $Config::Config{sig_name} and $Config::Config{sig_num} or die "No signals found"; - } - else { - my @names = split ' ', $Config{sig_name}; - @sig_num{@names} = split ' ', $Config{sig_num}; - } + + my @names = split ' ', $Config::Config{sig_name}; + my @nums = split ' ', $Config::Config{sig_num}; + + @sig_name2num{ @names } = @nums; + @sig_num2name{ @nums } = @names; } sub signame2num @@ -370,9 +377,19 @@ sub signame2num my $self = shift; my ( $signame ) = @_; - %sig_num or $self->_init_signum; + %sig_name2num or $self->_init_signum; + + return $sig_name2num{$signame}; +} + +sub signum2name +{ + my $self = shift; + my ( $signum ) = @_; + + %sig_num2name or $self->_init_signum; - return $sig_num{$signame}; + return $sig_num2name{$signum}; } =head2 extract_addrinfo diff --git a/lib/IO/Async/OS/MSWin32.pm b/lib/IO/Async/OS/MSWin32.pm index e7a1671..79c83ce 100644 --- a/lib/IO/Async/OS/MSWin32.pm +++ b/lib/IO/Async/OS/MSWin32.pm @@ -8,7 +8,7 @@ package IO::Async::OS::MSWin32; use strict; use warnings; -our $VERSION = '0.79'; +our $VERSION = '0.800'; our @ISA = qw( IO::Async::OS::_Base ); diff --git a/lib/IO/Async/OS/cygwin.pm b/lib/IO/Async/OS/cygwin.pm index fef6a4e..6111bfb 100644 --- a/lib/IO/Async/OS/cygwin.pm +++ b/lib/IO/Async/OS/cygwin.pm @@ -8,7 +8,7 @@ package IO::Async::OS::cygwin; use strict; use warnings; -our $VERSION = '0.79'; +our $VERSION = '0.800'; our @ISA = qw( IO::Async::OS::_Base ); diff --git a/lib/IO/Async/OS/linux.pm b/lib/IO/Async/OS/linux.pm index 74558e2..e58dc3c 100644 --- a/lib/IO/Async/OS/linux.pm +++ b/lib/IO/Async/OS/linux.pm @@ -8,7 +8,7 @@ package IO::Async::OS::linux; use strict; use warnings; -our $VERSION = '0.79'; +our $VERSION = '0.800'; our @ISA = qw( IO::Async::OS::_Base ); diff --git a/lib/IO/Async/PID.pm b/lib/IO/Async/PID.pm index c3416a6..007f903 100644 --- a/lib/IO/Async/PID.pm +++ b/lib/IO/Async/PID.pm @@ -9,7 +9,7 @@ use strict; use warnings; use base qw( IO::Async::Notifier ); -our $VERSION = '0.79'; +our $VERSION = '0.800'; use Carp; diff --git a/lib/IO/Async/Process.pm b/lib/IO/Async/Process.pm index 750c15d..286c051 100644 --- a/lib/IO/Async/Process.pm +++ b/lib/IO/Async/Process.pm @@ -9,7 +9,7 @@ use strict; use warnings; use base qw( IO::Async::Notifier ); -our $VERSION = '0.79'; +our $VERSION = '0.800'; use Carp; diff --git a/lib/IO/Async/Protocol.pm b/lib/IO/Async/Protocol.pm index 2751011..953b5c3 100644 --- a/lib/IO/Async/Protocol.pm +++ b/lib/IO/Async/Protocol.pm @@ -8,7 +8,7 @@ package IO::Async::Protocol; use strict; use warnings; -our $VERSION = '0.79'; +our $VERSION = '0.800'; use base qw( IO::Async::Notifier ); diff --git a/lib/IO/Async/Protocol/LineStream.pm b/lib/IO/Async/Protocol/LineStream.pm index 7c4bd0c..e92d208 100644 --- a/lib/IO/Async/Protocol/LineStream.pm +++ b/lib/IO/Async/Protocol/LineStream.pm @@ -8,7 +8,7 @@ package IO::Async::Protocol::LineStream; use strict; use warnings; -our $VERSION = '0.79'; +our $VERSION = '0.800'; use base qw( IO::Async::Protocol::Stream ); diff --git a/lib/IO/Async/Protocol/Stream.pm b/lib/IO/Async/Protocol/Stream.pm index 4a28f22..04773c3 100644 --- a/lib/IO/Async/Protocol/Stream.pm +++ b/lib/IO/Async/Protocol/Stream.pm @@ -8,7 +8,7 @@ package IO::Async::Protocol::Stream; use strict; use warnings; -our $VERSION = '0.79'; +our $VERSION = '0.800'; use base qw( IO::Async::Protocol ); diff --git a/lib/IO/Async/Resolver.pm b/lib/IO/Async/Resolver.pm index 5c04080..4df267a 100644 --- a/lib/IO/Async/Resolver.pm +++ b/lib/IO/Async/Resolver.pm @@ -9,7 +9,7 @@ use strict; use warnings; use base qw( IO::Async::Function ); -our $VERSION = '0.79'; +our $VERSION = '0.800'; # Socket 2.006 fails to getaddrinfo() AI_NUMERICHOST properly on MSWin32 use Socket 2.007 qw( diff --git a/lib/IO/Async/Routine.pm b/lib/IO/Async/Routine.pm index 72b8e14..ecf0383 100644 --- a/lib/IO/Async/Routine.pm +++ b/lib/IO/Async/Routine.pm @@ -8,7 +8,7 @@ package IO::Async::Routine; use strict; use warnings; -our $VERSION = '0.79'; +our $VERSION = '0.800'; use base qw( IO::Async::Notifier ); @@ -109,6 +109,8 @@ This model is only available on perls built to support threading. =head3 The C<spawn> model +I<Since version 0.79.> + The code in this model runs within its own freshly-created process running another copy of the perl interpreter. Similar to the C<fork> model it therefore has its own memory, CPU time, and other resources. However, since it @@ -123,9 +125,6 @@ In the current implementation this model requires exactly one input channel and exactly one output channel; both must be present, and there cannot be more than one of either. -This model performs well on both UNIX and Windows-like operating systems, -because it does not need full fork semantics. - =cut =head1 EVENTS @@ -190,6 +189,8 @@ and C<func> instead. =head2 func => STRING +I<Since version 0.79.> + An alternative to the C<code> argument, which names a module to load and a function to call within it. C<module> should give a perl module name (i.e. C<Some::Name>, not a filename like F<Some/Name.pm>), and C<func> should give @@ -413,7 +414,7 @@ sub _setup_thread code => sub { foreach ( @channels_in, @channels_out ) { $_->chan->setup_sync_mode( $_->otherfd ); - $_->myfd->close; + defined and $_->close for $_->myfd; } if( defined $func ) { diff --git a/lib/IO/Async/Signal.pm b/lib/IO/Async/Signal.pm index 089afec..51e260c 100644 --- a/lib/IO/Async/Signal.pm +++ b/lib/IO/Async/Signal.pm @@ -9,7 +9,7 @@ use strict; use warnings; use base qw( IO::Async::Notifier ); -our $VERSION = '0.79'; +our $VERSION = '0.800'; use Carp; diff --git a/lib/IO/Async/Socket.pm b/lib/IO/Async/Socket.pm index 5597f34..8b360fe 100644 --- a/lib/IO/Async/Socket.pm +++ b/lib/IO/Async/Socket.pm @@ -8,7 +8,7 @@ package IO::Async::Socket; use strict; use warnings; -our $VERSION = '0.79'; +our $VERSION = '0.800'; use base qw( IO::Async::Handle ); diff --git a/lib/IO/Async/Stream.pm b/lib/IO/Async/Stream.pm index 75c0900..9417fe4 100644 --- a/lib/IO/Async/Stream.pm +++ b/lib/IO/Async/Stream.pm @@ -8,7 +8,7 @@ package IO::Async::Stream; use strict; use warnings; -our $VERSION = '0.79'; +our $VERSION = '0.800'; use base qw( IO::Async::Handle ); diff --git a/lib/IO/Async/Test.pm b/lib/IO/Async/Test.pm index 3695ac9..dfb1cc0 100644 --- a/lib/IO/Async/Test.pm +++ b/lib/IO/Async/Test.pm @@ -8,7 +8,7 @@ package IO::Async::Test; use strict; use warnings; -our $VERSION = '0.79'; +our $VERSION = '0.800'; use Exporter 'import'; our @EXPORT = qw( diff --git a/lib/IO/Async/Timer.pm b/lib/IO/Async/Timer.pm index 7ef08c3..9af1bfa 100644 --- a/lib/IO/Async/Timer.pm +++ b/lib/IO/Async/Timer.pm @@ -9,7 +9,7 @@ use strict; use warnings; use base qw( IO::Async::Notifier ); -our $VERSION = '0.79'; +our $VERSION = '0.800'; use Carp; diff --git a/lib/IO/Async/Timer/Absolute.pm b/lib/IO/Async/Timer/Absolute.pm index d1b779a..b1da5e7 100644 --- a/lib/IO/Async/Timer/Absolute.pm +++ b/lib/IO/Async/Timer/Absolute.pm @@ -9,7 +9,7 @@ use strict; use warnings; use base qw( IO::Async::Timer ); -our $VERSION = '0.79'; +our $VERSION = '0.800'; use Carp; diff --git a/lib/IO/Async/Timer/Countdown.pm b/lib/IO/Async/Timer/Countdown.pm index 49b3a1d..53635a3 100644 --- a/lib/IO/Async/Timer/Countdown.pm +++ b/lib/IO/Async/Timer/Countdown.pm @@ -9,7 +9,7 @@ use strict; use warnings; use base qw( IO::Async::Timer ); -our $VERSION = '0.79'; +our $VERSION = '0.800'; use Carp; diff --git a/lib/IO/Async/Timer/Periodic.pm b/lib/IO/Async/Timer/Periodic.pm index 523303c..8f634cf 100644 --- a/lib/IO/Async/Timer/Periodic.pm +++ b/lib/IO/Async/Timer/Periodic.pm @@ -9,7 +9,7 @@ use strict; use warnings; use base qw( IO::Async::Timer ); -our $VERSION = '0.79'; +our $VERSION = '0.800'; use Carp; @@ -88,6 +88,7 @@ foreach my $family ( undef, "inet" ) { } is( IO::Async::OS->signame2num( 'TERM' ), SIGTERM, 'signame2num' ); +is( IO::Async::OS->signum2name( SIGTERM ), "TERM", 'signum2name' ); is( IO::Async::OS->getfamilybyname( "inet" ), AF_INET, 'getfamilybyname "inet"' ); is( IO::Async::OS->getfamilybyname( AF_INET ), AF_INET, 'getfamilybyname AF_INET' ); diff --git a/t/41routine.t b/t/41routine.t index b0f803b..ad5fee6 100644 --- a/t/41routine.t +++ b/t/41routine.t @@ -165,7 +165,7 @@ foreach my $model (qw( fork thread spawn )) { skip "This Perl does not support threads", 1 if $model eq "thread" and not IO::Async::OS->HAVE_THREADS; skip "This Perl does not support fork()", 1 - if $model eq "fork" and not IO::Async::OS->HAVE_POSIX_FORK; + if $model =~ m/fork|spawn/ and not IO::Async::OS->HAVE_POSIX_FORK; my $in = IO::Async::Channel->new; my $out = IO::Async::Channel->new; diff --git a/t/42function.t b/t/42function.t index 69eb919..dfa1c11 100644 --- a/t/42function.t +++ b/t/42function.t @@ -368,7 +368,7 @@ foreach my $model (qw( fork thread spawn )) { skip "This Perl does not support threads", 9 if $model eq "thread" and not IO::Async::OS->HAVE_THREADS; skip "This Perl does not support fork()", 9 - if $model eq "fork" and not IO::Async::OS->HAVE_POSIX_FORK; + if $model =~ m/fork|spawn/ and not IO::Async::OS->HAVE_POSIX_FORK; my $function = IO::Async::Function->new( model => $model, diff --git a/t/50resolver.t b/t/50resolver.t index 438b8d7..a90daa0 100644 --- a/t/50resolver.t +++ b/t/50resolver.t @@ -9,8 +9,9 @@ use Test::More; use Test::Metrics::Any; use Socket 1.93 qw( - AF_INET SOCK_STREAM SOCK_RAW INADDR_LOOPBACK AI_PASSIVE - pack_sockaddr_in inet_aton getaddrinfo getnameinfo + AF_INET SOCK_STREAM SOCK_DGRAM SOCK_RAW INADDR_LOOPBACK INADDR_ANY + AI_NUMERICHOST AI_PASSIVE NI_NUMERICHOST NI_NUMERICSERV + pack_sockaddr_in unpack_sockaddr_in sockaddr_family inet_aton inet_ntoa ); use IO::Async::Loop; @@ -131,36 +132,108 @@ SKIP: { is_deeply( $result, \@proto, 'getprotobynumber' ); } -# Some systems seem to mangle the order of results between PF_INET and -# PF_INET6 depending on who asks. We'll hint AF_INET + SOCK_STREAM to minimise -# the risk of a spurious test failure because of ordering issues +BEGIN { + # Rather than suffer various test failures because system resolver behaves + # in a weird way when testing, lets just mock it out and replace it with a + # virtual one so we can control the results + no warnings 'redefine'; -my ( $localhost_err, @localhost_addrs ) = getaddrinfo( "localhost", "www", { family => AF_INET, socktype => SOCK_STREAM } ); + *Socket::getaddrinfo = sub { + my ( $host, $service, $hints ) = @_; + + my $hint_flags = $hints->{flags} // 0; + my $hint_family = $hints->{family}; + my $hint_socktype = $hints->{socktype}; + + die "TODO: fake getaddrinfo on unrecognised family" if $hint_family and $hint_family != AF_INET; + + my $flag_numerichost = $hint_flags & AI_NUMERICHOST; + + return ( Socket::EAI_FAIL ) if $host =~ m/\.FAIL$/; + + my $inaddr; + $inaddr = inet_aton( "1.2.3.4" ) if !$flag_numerichost and $host eq "one.FAKE"; + $inaddr = INADDR_LOOPBACK if $host eq "127.0.0.1"; + $inaddr = INADDR_ANY if $hint_flags & AI_PASSIVE and !$host; + + defined $inaddr or + die "TODO: Unsure how to fake getaddrinfo on host=$host"; + + my $port = 0; + $port = $service+0 if $service =~ m/^\d+$/; + $port = 80 if $service eq "www"; + + my $addr = pack_sockaddr_in( $port, $inaddr ); + + my @res = map { + { family => AF_INET, socktype => $_, protocol => 0, addr => $addr } + } grep { !$hint_socktype or $_ == $hint_socktype } ( SOCK_STREAM, SOCK_DGRAM, SOCK_RAW ); + + return ( "", @res ); + }; + + *Socket::getnameinfo = sub { + my ( $addr, $flags ) = @_; + + my $family = sockaddr_family $addr; + $family == AF_INET or + die "TODO: Unsure how to fake getnameinfo on family=$family"; + + my ( $port, $inaddr ) = unpack_sockaddr_in $addr; + $inaddr eq INADDR_LOOPBACK or + die "TODO: Unsure how to fake getnameinfo on inaddr!=INADDR_LOOPBACK"; + + my $host; + if( $flags & NI_NUMERICHOST ) { + $host = inet_ntoa( $inaddr ); + } + else { + $host = "localhost"; + } + + my $service; + if( $flags & NI_NUMERICSERV ) { + $service = $port; + } + elsif( $port == 80 ) { + $service = "www"; + } + else { + die "TODO: convert port=$port to service name"; + } + + return ( "", $host, $service ); + }; +} + +my @expect_one_www = ( + { family => AF_INET, socktype => SOCK_STREAM, protocol => 0, addr => pack_sockaddr_in(80, inet_aton("1.2.3.4")) }, +); +my @expect_lo_80 = ( + { family => AF_INET, socktype => SOCK_STREAM, protocol => 0, addr => pack_sockaddr_in(80, INADDR_LOOPBACK) }, +); +my @expect_passive_3000 = ( + { family => AF_INET, socktype => 1, protocol => 0, addr => pack_sockaddr_in(3000, INADDR_ANY) }, +); { my $result; $resolver->resolve( type => 'getaddrinfo_array', - data => [ "localhost", "www", "inet", "stream" ], + data => [ "one.FAKE", "www", "inet", "stream" ], on_resolved => sub { $result = [ 'resolved', @_ ] }, on_error => sub { $result = [ 'error', @_ ] }, ); wait_for { $result }; - if( $localhost_err ) { - is( $result->[0], "error", 'getaddrinfo_array - error' ); - is_deeply( $result->[1], "$localhost_err", 'getaddrinfo_array - error message' ); - } - else { - is( $result->[0], "resolved", 'getaddrinfo_array - resolved' ); + is( $result->[0], "resolved", 'getaddrinfo_array - resolved' ); - my @got = @{$result}[1..$#$result]; - my @expect = map { [ @{$_}{qw( family socktype protocol addr canonname )} ] } @localhost_addrs; + my @got = @{$result}[1..$#$result]; + my @expect = map { [ @{$_}{qw( family socktype protocol addr canonname )} ] } @expect_one_www; - is_deeply( \@got, \@expect, 'getaddrinfo_array - resolved addresses' ); - } + is_deeply( \@got, \@expect, 'getaddrinfo_array - resolved addresses' ); } { @@ -168,31 +241,25 @@ my ( $localhost_err, @localhost_addrs ) = getaddrinfo( "localhost", "www", { fam $resolver->resolve( type => 'getaddrinfo_hash', - data => [ host => "localhost", service => "www", family => "inet", socktype => "stream" ], + data => [ host => "one.FAKE", service => "www", family => "inet", socktype => "stream" ], on_resolved => sub { $result = [ 'resolved', @_ ] }, on_error => sub { $result = [ 'error', @_ ] }, ); wait_for { $result }; - if( $localhost_err ) { - is( $result->[0], "error", 'getaddrinfo_hash - error' ); - is_deeply( $result->[1], "$localhost_err", 'getaddrinfo_hash - error message' ); - } - else { - is( $result->[0], "resolved", 'getaddrinfo_hash - resolved' ); + is( $result->[0], "resolved", 'getaddrinfo_hash - resolved' ); - my @got = @{$result}[1..$#$result]; + my @got = @{$result}[1..$#$result]; - is_deeply( \@got, \@localhost_addrs, 'getaddrinfo_hash - resolved addresses' ); - } + is_deeply( \@got, \@expect_one_www, 'getaddrinfo_hash - resolved addresses' ); } { my $result; $resolver->getaddrinfo( - host => "localhost", + host => "one.FAKE", service => "www", family => "inet", socktype => "stream", @@ -202,22 +269,16 @@ my ( $localhost_err, @localhost_addrs ) = getaddrinfo( "localhost", "www", { fam wait_for { $result }; - if( $localhost_err ) { - is( $result->[0], "error", '$resolver->getaddrinfo - error' ); - is_deeply( $result->[1], "$localhost_err", '$resolver->getaddrinfo - error message' ); - } - else { - is( $result->[0], "resolved", '$resolver->getaddrinfo - resolved' ); + is( $result->[0], "resolved", '$resolver->getaddrinfo - resolved' ); - my @got = @{$result}[1..$#$result]; + my @got = @{$result}[1..$#$result]; - is_deeply( \@got, \@localhost_addrs, '$resolver->getaddrinfo - resolved addresses' ); - } + is_deeply( \@got, \@expect_one_www, '$resolver->getaddrinfo - resolved addresses' ); } { my $future = $resolver->getaddrinfo( - host => "localhost", + host => "one.FAKE", service => "www", family => "inet", socktype => "stream", @@ -227,21 +288,12 @@ my ( $localhost_err, @localhost_addrs ) = getaddrinfo( "localhost", "www", { fam wait_for { $future->is_ready }; - if( $localhost_err ) { - is( scalar $future->failure, "$localhost_err", '$resolver->getaddrinfo - error message' ); - is( ( $future->failure )[1], "resolve", '->failure [1]' ); - is( ( $future->failure )[2], "getaddrinfo", '->failure [2]' ); - } - else { - my @got = $future->get; + my @got = $future->get; - is_deeply( \@got, \@localhost_addrs, '$resolver->getaddrinfo - resolved addresses' ); - } + is_deeply( \@got, \@expect_one_www, '$resolver->getaddrinfo - resolved addresses' ); } { - my ( $lo_err, @lo_addrs ) = getaddrinfo( "127.0.0.1", "80", { socktype => SOCK_STREAM } ); - my $result; $resolver->getaddrinfo( @@ -256,7 +308,9 @@ my ( $localhost_err, @localhost_addrs ) = getaddrinfo( "localhost", "www", { fam my @got = @{$result}[1..$#$result]; - is_deeply( \@got, \@lo_addrs, '$resolver->getaddrinfo resolved addresses synchronously' ); + use Data::Dump 'pp'; + + is_deeply( \@got, \@expect_lo_80, '$resolver->getaddrinfo resolved addresses synchronously' ); undef $result; $resolver->getaddrinfo( @@ -275,8 +329,6 @@ my ( $localhost_err, @localhost_addrs ) = getaddrinfo( "localhost", "www", { fam } { - my ( $passive_err, @passive_addrs ) = getaddrinfo( "", "3000", { socktype => SOCK_STREAM, family => AF_INET, flags => AI_PASSIVE } ); - my $result; $resolver->getaddrinfo( @@ -288,22 +340,15 @@ my ( $localhost_err, @localhost_addrs ) = getaddrinfo( "localhost", "www", { fam on_error => sub { $result = [ 'error', @_ ] }, ); - if( $passive_err ) { - is( $result->[0], "error", '$resolver->getaddrinfo passive - error synchronously' ); - is_deeply( $result->[1], "$passive_err", '$resolver->getaddrinfo passive - error message' ); - } - else { - is( $result->[0], "resolved", '$resolver->getaddrinfo passive - resolved synchronously' ); + is( $result->[0], "resolved", '$resolver->getaddrinfo passive - resolved synchronously' ); - my @got = @{$result}[1..$#$result]; + my @got = @{$result}[1..$#$result]; - is_deeply( \@got, \@passive_addrs, '$resolver->getaddrinfo passive - resolved addresses' ); - } + is_deeply( \@got, \@expect_passive_3000, '$resolver->getaddrinfo passive - resolved addresses' ) or + diag( "Got=", pp(\@got), "; expected=", pp(\@expect_passive_3000) ); } { - my ( $lo_err, @lo_addrs ) = getaddrinfo( "127.0.0.1", "80", { socktype => SOCK_STREAM } ); - my $future = $resolver->getaddrinfo( host => "127.0.0.1", service => "80", @@ -316,20 +361,12 @@ my ( $localhost_err, @localhost_addrs ) = getaddrinfo( "localhost", "www", { fam my @got = $future->get; - is_deeply( \@got, \@lo_addrs, '$resolver->getaddrinfo resolved addresses synchronously' ); + is_deeply( \@got, \@expect_lo_80, '$resolver->getaddrinfo resolved addresses synchronously' ); } -# Now something I hope doesn't exist - we put it in a known-missing TLD -my $missinghost = "TbK4jM2M0OS.lm57DWIyu4i"; - -# Some CPAN testing machines seem to have wildcard DNS servers that reply to -# any request. We'd better check for them - -SKIP: { - skip "Resolver has an answer for $missinghost", 1 if gethostbyname( $missinghost ); - +{ my $future = wait_for_future $resolver->getaddrinfo( - host => $missinghost, + host => "a-name-to.FAIL", service => "80", socktype => SOCK_STREAM, ); @@ -339,58 +376,41 @@ SKIP: { is( ( $future->failure )[2], "getaddrinfo", '->failure [2] gives getaddrinfo' ); my $errno = ( $future->failure )[3]; - ok( $errno == Socket::EAI_FAIL || $errno == Socket::EAI_AGAIN || # no server available - $errno == Socket::EAI_NONAME || $errno == Socket::EAI_NODATA, # server confirmed no DNS entry - '->failure [3] gives EAI_FAIL or EAI_AGAIN or EAI_NONAME or EAI_NODATA' ) or - diag( '$errno is ' . $errno ); + is( $errno, Socket::EAI_FAIL, '->failure [3] gives EAI_FAIL' ); } -my $testaddr = pack_sockaddr_in( 80, INADDR_LOOPBACK ); -my ( $testerr, $testhost, $testserv ) = getnameinfo( $testaddr ); +my $sinaddr_lo_www = pack_sockaddr_in( 80, INADDR_LOOPBACK ); { my $result; $resolver->getnameinfo( - addr => $testaddr, + addr => $sinaddr_lo_www, on_resolved => sub { $result = [ 'resolved', @_ ] }, on_error => sub { $result = [ 'error', @_ ] }, ); wait_for { $result }; - if( $testerr ) { - is( $result->[0], "error", '$resolver->getnameinfo - error' ); - is_deeply( $result->[1], "$testerr", '$resolver->getnameinfo - error message' ); - } - else { - is( $result->[0], "resolved", '$resolver->getnameinfo - resolved' ); - is_deeply( [ @{$result}[1..2] ], [ $testhost, $testserv ], '$resolver->getnameinfo - resolved names' ); - } + is( $result->[0], "resolved", '$resolver->getnameinfo - resolved' ); + is_deeply( [ @{$result}[1..2] ], [ "localhost", "www" ], '$resolver->getnameinfo - resolved names' ); } { my $future = wait_for_future $resolver->getnameinfo( - addr => $testaddr, + addr => $sinaddr_lo_www, ); - if( $testerr ) { - is( scalar $future->failure, "$testerr", '$resolver->getnameinfo - error message from future' ); - is( ( $future->failure )[1], "resolve", '->failure [1]' ); - is( ( $future->failure )[2], "getnameinfo", '->failure [2]' ); - } - else { - my @got = $future->get; + my @got = $future->get; - is_deeply( \@got, [ $testhost, $testserv ], '$resolver->getnameinfo - resolved names from future' ); - } + is_deeply( \@got, [ "localhost", "www" ], '$resolver->getnameinfo - resolved names from future' ); } { my $result; $resolver->getnameinfo( - addr => $testaddr, + addr => $sinaddr_lo_www, numeric => 1, on_resolved => sub { $result = [ 'resolved', @_ ] }, on_error => sub { $result = [ 'error', @_ ] }, @@ -401,7 +421,7 @@ my ( $testerr, $testhost, $testserv ) = getnameinfo( $testaddr ); { my $future = $resolver->getnameinfo( - addr => $testaddr, + addr => $sinaddr_lo_www, numeric => 1, ); @@ -414,7 +434,7 @@ SKIP: { is_metrics_from( sub { - $resolver->getnameinfo( addr => $testaddr )->get; + $resolver->getnameinfo( addr => $sinaddr_lo_www )->get; }, { "io_async_resolver_lookups type:getnameinfo" => 1 }, 'Resolver increments metrics' diff --git a/t/70future-io.t b/t/70future-io.t index 7154c6d..ee9cf36 100644 --- a/t/70future-io.t +++ b/t/70future-io.t @@ -6,6 +6,7 @@ use warnings; use IO::Async::Test; use Test::More; +use Test::Future::IO::Impl; use lib "."; use t::TimeAbout; @@ -63,4 +64,6 @@ testing_loop( IO::Async::Loop->new_builtin ); is( $buf, "ABCD", 'Future::IO->syswrite wrote data' ); } +run_tests qw( sleep sysread syswrite waitpid ); + done_testing; |