@@ -9,6 +9,25 @@ TODO: AnyEvent::Handle with AnyEvent::IO?
TODO: invalid. and localhost. specialcasing inside AEDNS and not AESocket (rfc6761)
TODO: maybe implement env variable to give hosts precedence
+7.08 Wed Dec 10 05:27:17 CET 2014
+ - work around a newly introduced bug in Socket 2.011 (an
+ errornous sun_length check) (analyzed by Maxime Soulé).
+ - AnyEvent::TLS didn't load (but refer to) AnyEvent::Socket
+ (analyzed by Ben Magistro).
+ - AnyEvent::Strict will now confess, not croak. This is in line with
+ it being a development/debugging tool.
+ - work around a number of libglib bugs (debug builds of libglib enforce
+ certain undocumented behaviour patterns such as not being able to
+ remove a child watch source after it has fired, which we will try
+ to emulate to avoid "criticals". what where they thinking...).
+ - mention json security issues in AnyEvent::Handle, now that Douglas
+ Crockford has foolishly and incompatibly changed JSON.
+ - changed default dns resolver "max_outstanding" value from 1 to 10,
+ the latter beinfg the intended value all along
+ (reported by Ilya Chesnokov).
+ - added new "AnyEvent::Impl::UV" interface module to the UV event lib
+ (written by Mike Lowell).
+
7.07 Tue Dec 17 17:45:02 CET 2013
- the documentation for custom tls verify schemes was wrong. make it agree
with the code (reported by Maxime Soulé).
@@ -630,7 +649,7 @@ TODO: maybe implement env variable to give hosts precedence
- add an additional error message parameter to AnyEvent::Handle's
on_error callback (for TLS, $! is still available).
- add AnyEvent::Handle on_starttls/on_stoptls callbacks.
- - make AnyEvent::Handle more robust against early conenction
+ - make AnyEvent::Handle more robust against early connection
failures (during new), and return C<undef> in that case
from the constructor.
- AnyEvent::Handle will now try to load only JSON::XS first,
@@ -23,6 +23,7 @@ lib/AnyEvent/Impl/POE.pm
lib/AnyEvent/Impl/Perl.pm
lib/AnyEvent/Impl/Qt.pm
lib/AnyEvent/Impl/Tk.pm
+lib/AnyEvent/Impl/UV.pm
lib/AnyEvent/IO.pm
lib/AnyEvent/IO/IOAIO.pm
lib/AnyEvent/IO/Perl.pm
@@ -128,5 +129,13 @@ t/69_ev_04_condvar.t
t/69_ev_05_dns.t
t/69_ev_07_io.t
t/69_ev_09_multi.t
+t/70_uv_01_basic.t
+t/70_uv_02_signals.t
+t/70_uv_03_child.t
+t/70_uv_04_condvar.t
+t/70_uv_05_dns.t
+t/70_uv_07_io.t
+t/70_uv_09_multi.t
+
META.yml Module YAML meta-data (added by MakeMaker)
META.json Module JSON meta-data (added by MakeMaker)
@@ -4,7 +4,7 @@
"unknown"
],
"dynamic_config" : 1,
- "generated_by" : "ExtUtils::MakeMaker version 6.8, CPAN::Meta::Converter version 2.120921",
+ "generated_by" : "ExtUtils::MakeMaker version 6.98, CPAN::Meta::Converter version 2.142060",
"license" : [
"unknown"
],
@@ -44,5 +44,5 @@
}
},
"release_status" : "stable",
- "version" : "7.07"
+ "version" : "7.08"
}
@@ -3,27 +3,27 @@ abstract: unknown
author:
- unknown
build_requires:
- ExtUtils::MakeMaker: 0
+ ExtUtils::MakeMaker: '0'
configure_requires:
- ExtUtils::MakeMaker: 0
+ ExtUtils::MakeMaker: '0'
dynamic_config: 1
-generated_by: 'ExtUtils::MakeMaker version 6.8, CPAN::Meta::Converter version 2.120921'
+generated_by: 'ExtUtils::MakeMaker version 6.98, CPAN::Meta::Converter version 2.142060'
license: unknown
meta-spec:
url: http://module-build.sourceforge.net/META-spec-v1.4.html
- version: 1.4
+ version: '1.4'
name: AnyEvent
no_index:
directory:
- t
- inc
recommends:
- Async::Interrupt: 1
- EV: 4
- Guard: 1.02
- JSON: 2.09
- JSON::XS: 2.2
- Net::SSLeay: 1.33
- Task::Weaken: 0
+ Async::Interrupt: '1'
+ EV: '4'
+ Guard: '1.02'
+ JSON: '2.09'
+ JSON::XS: '2.2'
+ Net::SSLeay: '1.33'
+ Task::Weaken: '0'
requires: {}
-version: 7.07
+version: '7.08'
@@ -67,6 +67,7 @@ WriteMakefile(
'lib/AnyEvent/Impl/Perl.pm' => '$(INST_LIB)/AnyEvent/Impl/Perl.pm',
'lib/AnyEvent/Impl/Qt.pm' => '$(INST_LIB)/AnyEvent/Impl/Qt.pm',
'lib/AnyEvent/Impl/Tk.pm' => '$(INST_LIB)/AnyEvent/Impl/Tk.pm',
+ 'lib/AnyEvent/Impl/UV.pm' => '$(INST_LIB)/AnyEvent/Impl/UV.pm',
'lib/AnyEvent/IO.pm' => '$(INST_LIB)/AnyEvent/IO.pm',
'lib/AnyEvent/IO/IOAIO.pm' => '$(INST_LIB)/AnyEvent/IO/IOAIO.pm',
'lib/AnyEvent/IO/Perl.pm' => '$(INST_LIB)/AnyEvent/IO/Perl.pm',
@@ -1,8 +1,9 @@
NAME
AnyEvent - the DBI of event loop programming
- EV, Event, Glib, Tk, Perl, Event::Lib, Irssi, rxvt-unicode, IO::Async,
- Qt, FLTK and POE are various supported event loops/environments.
+ EV, Event, Glib, Tk, UV, Perl, Event::Lib, Irssi, rxvt-unicode,
+ IO::Async, Qt, FLTK and POE are various supported event
+ loops/environments.
SYNOPSIS
use AnyEvent;
@@ -845,6 +846,7 @@ SUPPORTED EVENT LOOPS/BACKENDS
AnyEvent::Impl::Event based on Event, very stable, few glitches.
AnyEvent::Impl::Glib based on Glib, slow but very stable.
AnyEvent::Impl::Tk based on Tk, very broken.
+ AnyEvent::Impl::UV based on UV, innovated square wheels.
AnyEvent::Impl::EventLib based on Event::Lib, leaks memory and worse.
AnyEvent::Impl::POE based on POE, very slow, some limitations.
AnyEvent::Impl::Irssi used when running within irssi.
@@ -986,7 +988,7 @@ GLOBAL VARIABLES AND FUNCTIONS
transaction object or guard to let you cancel the operation. For
example, "AnyEvent::Socket::tcp_connect":
- # start a conenction attempt unless one is active
+ # start a connection attempt unless one is active
$self->{connect_guard} ||= AnyEvent::Socket::tcp_connect "www.example.net", 80, sub {
delete $self->{connect_guard};
...
@@ -1360,7 +1362,7 @@ ENVIRONMENT VARIABLES
This variable can effectively be used for denial-of-service attacks
against local programs (e.g. when setuid), although the impact is
- likely small, as the program has to handle conenction and other
+ likely small, as the program has to handle connection and other
failures anyways.
Examples: "PERL_ANYEVENT_PROTOCOLS=ipv4,ipv6" - prefer IPv4 over
@@ -698,7 +698,7 @@ resolver object.
The resolver is created with the following parameters:
untaint enabled
- max_outstanding $ENV{PERL_ANYEVENT_MAX_OUTSTANDING_DNS}
+ max_outstanding $ENV{PERL_ANYEVENT_MAX_OUTSTANDING_DNS} (default 10)
C<os_config> will be used for OS-specific configuration, unless
C<$ENV{PERL_ANYEVENT_RESOLV_CONF}> is specified, in which case that file
@@ -722,7 +722,7 @@ sub resolver() {
$RESOLVER || do {
$RESOLVER = new AnyEvent::DNS
untaint => 1,
- max_outstanding => $ENV{PERL_ANYEVENT_MAX_OUTSTANDING_DNS}*1 || 1,
+ max_outstanding => $ENV{PERL_ANYEVENT_MAX_OUTSTANDING_DNS}*1 || 10,
;
$ENV{PERL_ANYEVENT_RESOLV_CONF}
@@ -46,7 +46,7 @@ our %STRCACHE;
This function binds on the given host and service port and returns a
shell object, which determines the lifetime of the shell. Any number
-of conenctions are accepted on the port, and they will give you a very
+of connections are accepted on the port, and they will give you a very
primitive shell that simply executes every line you enter.
All commands will be executed "blockingly" with the socket C<select>ed for
@@ -134,9 +134,6 @@ parameters, together with a retry callback. At the time it is called the
read and write queues, EOF status, TLS status and similar properties of
the handle will have been reset.
-It is not allowed to use the read or write queues while the handle object
-is connecting.
-
If, for some reason, the handle is not acceptable, calling C<$retry> will
continue with the next connection target (in case of multi-homed hosts or
SRV records there can be multiple connection endpoints). The C<$retry>
@@ -503,8 +500,26 @@ underlying handle signals EOF.
This is the json coder object used by the C<json> read and write types.
If you don't supply it, then AnyEvent::Handle will create and use a
-suitable one (on demand), which will write and expect UTF-8 encoded JSON
-texts.
+suitable one (on demand), which will write and expect UTF-8 encoded
+JSON texts (either using L<JSON::XS> or L<JSON>). The written texts are
+guaranteed not to contain any newline character.
+
+For security reasons, this encoder will likely I<not> handle numbers and
+strings, only arrays and objects/hashes. The reason is that originally
+JSON was self-delimited, but Dougles Crockford thought it was a splendid
+idea to redefine JSON incompatibly, so this is no longer true.
+
+For protocols that used back-to-back JSON texts, this might lead to
+run-ins, where two or more JSON texts will be interpreted as one JSON
+text.
+
+For this reason, if the default encoder uses L<JSON::XS>, it will default
+to not allowing anything but arrays and objects/hashes, at least for the
+forseeable future (it will change at some point). This might or might not
+be true for the L<JSON> module, so this might cause a security issue.
+
+If you depend on either behaviour, you should create your own json object
+and pass it in explicitly.
=item cbor => L<CBOR::XS> object
@@ -512,7 +527,7 @@ This is the cbor coder object used by the C<cbor> read and write types.
If you don't supply it, then AnyEvent::Handle will create and use a
suitable one (on demand), which will write CBOR without using extensions,
-if possible. texts.
+if possible.
Note that you are responsible to depend on the L<CBOR::XS> module if you
want to use this functionality, as AnyEvent does not have a dependency on
@@ -1056,13 +1071,18 @@ Encodes the given hash or array reference into a JSON object. Unless you
provide your own JSON object, this means it will be encoded to JSON text
in UTF-8.
-JSON objects (and arrays) are self-delimiting, so you can write JSON at
-one end of a handle and read them at the other end without using any
-additional framing.
+The default encoder might or might not handle every type of JSON value -
+it might be limited to arrays and objects for security reasons. See the
+C<json> constructor attribute for more details.
+
+JSON objects (and arrays) are self-delimiting, so if you only use arrays
+and hashes, you can write JSON at one end of a handle and read them at the
+other end without using any additional framing.
-The generated JSON text is guaranteed not to contain any newlines: While
-this module doesn't need delimiters after or between JSON texts to be
-able to read them, many other languages depend on that.
+The JSON text generated by the default encoder is guaranteed not to
+contain any newlines: While this module doesn't need delimiters after or
+between JSON texts to be able to read them, many other languages depend on
+them.
A simple RPC protocol that interoperates easily with other languages is
to send JSON arrays (or objects, although arrays are usually the better
@@ -19,10 +19,22 @@ Glib is probably the most inefficient event loop that has ever seen the
light of the world: Glib not only scans all its watchers (really, ALL of
them, whether I/O-related, timer-related or what not) during each loop
iteration, it also does so multiple times and rebuilds the poll list for
-the kernel each time again, dynamically even.
+the kernel each time again, dynamically even. Newer versions of libglib
+fortunately do not call malloc/free on every single watcher invocation,
+though.
-On the positive side, and most importantly, Glib generally works
-correctly, no quarrels there.
+Glib also enforces certain undocumented behaviours, for example, you
+cannot always remove active child watchers, and the conditions on when
+it is valid to do so are not documented. Of course, if you get it wrong,
+you get "GLib-CRITICAL" messages. This makes it extremely hard to write
+"correct" glib programs, as you have to study the source code to get it
+right, and hope future versions don't change any internals.
+
+AnyEvent implements the necessary workarounds, at a small performance
+cost.
+
+On the positive side, and most importantly, when it works, Glib generally
+works correctly, no quarrels there.
If you create many watchers (as in: more than two), you might consider one
of the L<Glib::EV>, L<EV::Glib> or L<Glib::Event> modules that map Glib to
@@ -70,9 +82,18 @@ sub timer {
remove Glib::Source $source;
$source = add Glib::Timeout $ival, sub { &$cb; 1 };
&$cb;
- 0
+ 1 # already removed, should be a nop
}
- : sub { &$cb; 0 };
+ : sub {
+ # due to the braindamaged libglib API (it manages
+ # removed-but-active watchers internally, but forces
+ # users to # manage the same externally as well),
+ # we have to go through these contortions.
+ remove Glib::Source $source;
+ undef $source;
+ &$cb;
+ 1 # already removed, should be a nop
+ };
bless \\$source, $class
}
@@ -87,7 +108,8 @@ sub idle {
}
sub DESTROY {
- remove Glib::Source $${$_[0]};
+ remove Glib::Source $${$_[0]}
+ if defined $${$_[0]};
}
our %pid_w;
@@ -105,10 +127,16 @@ sub child {
$pid_cb{$pid}{$cb+0} = $cb;
$pid_w{$pid} ||= Glib::Child->watch_add ($pid, sub {
+ # the unbelievably braindamaged glib api ignores the return
+ # value and always removes the watcher (this is of course
+ # undocumented), so we need to go through these contortions to
+ # work around this, here and in DESTROY.
+ undef $pid_w{$pid};
+
$_->($_[0], $_[1])
for values %{ $pid_cb{$pid} };
- 1
+ 1 # gets ignored
});
bless [$pid, $cb+0], "AnyEvent::Impl::Glib::child"
@@ -120,7 +148,8 @@ sub AnyEvent::Impl::Glib::child::DESTROY {
delete $pid_cb{$pid}{$icb};
unless (%{ $pid_cb{$pid} }) {
delete $pid_cb{$pid};
- remove Glib::Source delete $pid_w{$pid};
+ my $source = delete $pid_w{$pid};
+ remove Glib::Source if defined $source;
}
}
@@ -0,0 +1,175 @@
+=head1 NAME
+
+AnyEvent::Impl::UV - AnyEvent adaptor for UV
+
+=head1 SYNOPSIS
+
+ use AnyEvent;
+ use UV;
+
+ # this module gets loaded automatically as required
+
+=head1 DESCRIPTION
+
+This module provides transparent support for AnyEvent. You don't have to
+do anything to make UV work with AnyEvent except by loading UV before
+creating the first AnyEvent watcher.
+
+=cut
+
+package AnyEvent::Impl::UV;
+
+use AnyEvent (); BEGIN { AnyEvent::common_sense }
+use UV 0.24;
+use Scalar::Util qw(weaken);
+
+sub warnlog {
+ my $err = UV::last_error;
+
+ AnyEvent::log warn => "returned $_[0]: "
+ . UV::err_name ($err) . "($err): "
+ . UV::strerror ($err);
+
+ @_
+}
+
+# https://github.com/joyent/libuv/issues/680
+# https://github.com/joyent/libuv/blob/dc1ea27c736f0d21c7160c790bcd1b113d20abd9/include/uv.h#L1277
+my %io_watchers;
+
+sub io_watcher_cb {
+ my $slaves = shift;
+ my (undef, $events) = @_;
+ return unless defined $slaves;
+
+ foreach my $entry (keys %$slaves) {
+ my $slave = $slaves->{$entry};
+ $slave->{cb}(@_) if $slave->{mode} & $events;
+ }
+}
+
+sub AnyEvent::Impl::UV::io_slave::new {
+ bless { parent => $_[1] }, $_[0]
+}
+
+sub AnyEvent::Impl::UV::io_slave::DESTROY {
+ my $self = $_[0];
+ my $master = $self->{parent};
+
+ delete $master->{slaves}{$self};
+ if (keys %{$master->{slaves}} == 0) {
+ if (defined $master->{w}) {
+ my $rc = UV::poll_stop $master->{w};
+ warnlog $rc if $rc;
+ }
+ delete $io_watchers{$master->{fd}};
+ return;
+ }
+
+ my $mode = 0;
+ foreach my $entry (keys %{$master->{slaves}}) {
+ $mode |= $master->{slaves}{$entry}{mode};
+ }
+
+ if ($master->{mode} != $mode) {
+ $master->{mode} = $mode;
+ my $rc = UV::poll_start $master->{w}, $master->{mode}, sub {
+ io_watcher_cb $master->{slaves}, @_;
+ };
+ warnlog $rc if $rc;
+ }
+}
+
+sub io {
+ my ($class, %arg) = @_;
+ my $fd = fileno $arg{fh};
+ defined $fd or $fd = $arg{fh};
+
+ my $master = $io_watchers{$fd} ||= { fd => $fd };
+
+ unless (defined $master->{w}) {
+ $master->{w} = UV::poll_init $fd;
+ return warnlog $master->{w} unless defined $master->{w};
+ $master->{slaves} = {};
+ }
+
+ my $slave = AnyEvent::Impl::UV::io_slave->new ($master);
+ weaken ($master->{slaves}->{$slave} = $slave);
+
+ $slave->{mode} = $arg{poll} eq "r" ? UV::READABLE : UV::WRITABLE;
+ $master->{mode} = 0 unless defined $master->{mode};
+ $slave->{cb} = $arg{cb};
+
+ unless ($master->{mode} & $slave->{mode}) {
+ $master->{mode} |= $slave->{mode};
+ my $rc = UV::poll_start $master->{w}, $master->{mode}, sub {
+ io_watcher_cb $master->{slaves}, @_;
+ };
+ warnlog $rc if $rc;
+ }
+
+ $slave
+}
+
+sub AnyEvent::Impl::UV::handle::new {
+ my ($class, $w, $start, $stop, @args) = @_;
+ return warnlog $w unless defined $w;
+
+ my $rc = $start->($w, @args);
+ warnlog $rc if $rc;
+
+ bless { w => $w, stop => $stop }, $class
+}
+
+sub AnyEvent::Impl::UV::handle::DESTROY {
+ my $h = $_[0];
+ return unless $h->{w};
+ my $rc = $h->{stop}($h->{w});
+ warnlog $rc if $rc;
+ UV::close $h->{w};
+}
+
+sub idle {
+ my ($class, %arg) = @_;
+
+ AnyEvent::Impl::UV::handle->new (
+ UV::timer_init,
+ \&UV::idle_start,
+ \&UV::idle_stop,
+ $arg{cb}
+ );
+}
+
+sub timer {
+ my ($class, %arg) = @_;
+
+ AnyEvent::Impl::UV::handle->new (
+ UV::timer_init,
+ \&UV::timer_start,
+ \&UV::timer_stop,
+ $arg{after} * 1000, $arg{interval} * 1000, $arg{cb}
+ );
+}
+
+sub now { UV::now }
+
+sub _poll {
+ UV::run UV::RUN_ONCE;
+}
+
+sub AnyEvent::CondVar::Base::_wait {
+ UV::run UV::RUN_NOWAIT until exists $_[0]{_ae_sent};
+}
+
+=head1 SEE ALSO
+
+L<AnyEvent>, L<UV>.
+
+=head1 AUTHOR
+
+ Mike Lowell <mikedotlowell@gmail.com>
+
+=cut
+
+1
+
@@ -175,7 +175,7 @@ in scope when a closure is created can be used inside the closure:
call_me_back_later sub { $arg->method };
Under most circumstances, closures are faster, use fewer resources and
-result in much clearer code then the traditional approach. Faster,
+result in much clearer code than the traditional approach. Faster,
because parameter passing and storing them in local variables in Perl
is relatively slow. Fewer resources, because closures take references
to existing variables without having to create new ones, and clearer
@@ -485,7 +485,7 @@ function.
This is the function that is called after logging a C<fatal> log
message. It must not return.
-The default implementation simpl calls C<exit 1>.
+The default implementation simply calls C<exit 1>.
In your main program (as opposed to in your module) you can override
the fatal exit function by loading this module and then redefining this
@@ -578,8 +578,14 @@ module (C<format_address> converts it to C<unix/>).
# perl contains a bug (imho) where it requires that the kernel always returns
# sockaddr_un structures of maximum length (which is not, AFAICS, required
# by any standard). try to 0-pad structures for the benefit of those platforms.
+# unfortunately, the IO::Async author chose to break Socket again in version
+# 2.011 - it now contains a bogus length check, so we disable the workaround.
-my $sa_un_zero = eval { Socket::pack_sockaddr_un "" }; $sa_un_zero ^= $sa_un_zero;
+my $sa_un_zero = $Socket::VERSION >= 2.011
+ ? ""
+ : eval { Socket::pack_sockaddr_un "" };
+
+$sa_un_zero ^= $sa_un_zero;
sub unpack_sockaddr($) {
my $af = sockaddr_family $_[0];
@@ -595,7 +601,7 @@ sub unpack_sockaddr($) {
}
}
-=item resolve_sockaddr $node, $service, $proto, $family, $type, $cb->([$family, $type, $proto, $sockaddr], ...)
+=item AnyEvent::Socket::resolve_sockaddr $node, $service, $proto, $family, $type, $cb->([$family, $type, $proto, $sockaddr], ...)
Tries to resolve the given nodename and service name into protocol families
and sockaddr structures usable to connect to this node and service in a
@@ -904,9 +910,6 @@ in not-yet-connected state as only argument and must return the connection
timeout value (or C<0>, C<undef> or the empty list to indicate the default
timeout is to be used).
-Note that the socket could be either a IPv4 TCP socket or an IPv6 TCP
-socket (although only IPv4 is currently supported by this module).
-
Note to the poor Microsoft Windows users: Windows (of course) doesn't
correctly signal connection errors, so unless your event library works
around this, failed connections will simply hang. The only event libraries
@@ -24,10 +24,13 @@ L<AnyEvent>). However, this module can be loaded manually at any time.
package AnyEvent::Strict;
-use Carp qw(croak);
+use Carp qw(confess);
use Errno ();
use POSIX ();
+$Carp::Internal{AE} = 1;
+$Carp::Internal{AnyEvent::Strict} = 1;
+
use AnyEvent (); BEGIN { AnyEvent::common_sense }
AnyEvent::_isa_hook 1 => "AnyEvent::Strict", 1;
@@ -93,11 +96,11 @@ sub io {
my (%arg, $fh, $cb, $fd) = @_;
ref $arg{cb}
- or croak "AnyEvent->io called with illegal cb argument '$arg{cb}'";
+ or confess "AnyEvent->io called with illegal cb argument '$arg{cb}'";
$cb = wrap delete $arg{cb};
$arg{poll} =~ /^[rw]$/
- or croak "AnyEvent->io called with illegal poll argument '$arg{poll}'";
+ or confess "AnyEvent->io called with illegal poll argument '$arg{poll}'";
$fh = delete $arg{fh};
@@ -106,15 +109,15 @@ sub io {
$fh = AnyEvent::_dupfh $arg{poll}, $fh;
} else {
defined eval { $fd = fileno $fh }
- or croak "AnyEvent->io called with illegal fh argument '$fh'";
+ or confess "AnyEvent->io called with illegal fh argument '$fh'";
}
-f $fh
- and croak "AnyEvent->io called with fh argument pointing to a file";
+ and confess "AnyEvent->io called with fh argument pointing to a file";
delete $arg{poll};
- croak "AnyEvent->io called with unsupported parameter(s) " . join ", ", keys %arg
+ confess "AnyEvent->io called with unsupported parameter(s) " . join ", ", keys %arg
if keys %arg;
++$FD_INUSE[$fd];
@@ -134,18 +137,18 @@ sub timer {
my %arg = @_;
ref $arg{cb}
- or croak "AnyEvent->timer called with illegal cb argument '$arg{cb}'";
+ or confess "AnyEvent->timer called with illegal cb argument '$arg{cb}'";
my $cb = wrap delete $arg{cb};
exists $arg{after}
- or croak "AnyEvent->timer called without mandatory 'after' parameter";
+ or confess "AnyEvent->timer called without mandatory 'after' parameter";
delete $arg{after};
!$arg{interval} or $arg{interval} > 0
- or croak "AnyEvent->timer called with illegal interval argument '$arg{interval}'";
+ or confess "AnyEvent->timer called with illegal interval argument '$arg{interval}'";
delete $arg{interval};
- croak "AnyEvent->timer called with unsupported parameter(s) " . join ", ", keys %arg
+ confess "AnyEvent->timer called with unsupported parameter(s) " . join ", ", keys %arg
if keys %arg;
$class->SUPER::timer (@_, cb => $cb)
@@ -156,14 +159,14 @@ sub signal {
my %arg = @_;
ref $arg{cb}
- or croak "AnyEvent->signal called with illegal cb argument '$arg{cb}'";
+ or confess "AnyEvent->signal called with illegal cb argument '$arg{cb}'";
my $cb = wrap delete $arg{cb};
defined AnyEvent::Base::sig2num $arg{signal} and $arg{signal} == 0
- or croak "AnyEvent->signal called with illegal signal name '$arg{signal}'";
+ or confess "AnyEvent->signal called with illegal signal name '$arg{signal}'";
delete $arg{signal};
- croak "AnyEvent->signal called with unsupported parameter(s) " . join ", ", keys %arg
+ confess "AnyEvent->signal called with unsupported parameter(s) " . join ", ", keys %arg
if keys %arg;
$class->SUPER::signal (@_, cb => $cb)
@@ -174,14 +177,14 @@ sub child {
my %arg = @_;
ref $arg{cb}
- or croak "AnyEvent->child called with illegal cb argument '$arg{cb}'";
+ or confess "AnyEvent->child called with illegal cb argument '$arg{cb}'";
my $cb = wrap delete $arg{cb};
$arg{pid} =~ /^-?\d+$/
- or croak "AnyEvent->child called with malformed pid value '$arg{pid}'";
+ or confess "AnyEvent->child called with malformed pid value '$arg{pid}'";
delete $arg{pid};
- croak "AnyEvent->child called with unsupported parameter(s) " . join ", ", keys %arg
+ confess "AnyEvent->child called with unsupported parameter(s) " . join ", ", keys %arg
if keys %arg;
$class->SUPER::child (@_, cb => $cb)
@@ -192,10 +195,10 @@ sub idle {
my %arg = @_;
ref $arg{cb}
- or croak "AnyEvent->idle called with illegal cb argument '$arg{cb}'";
+ or confess "AnyEvent->idle called with illegal cb argument '$arg{cb}'";
my $cb = wrap delete $arg{cb};
- croak "AnyEvent->idle called with unsupported parameter(s) " . join ", ", keys %arg
+ confess "AnyEvent->idle called with unsupported parameter(s) " . join ", ", keys %arg
if keys %arg;
$class->SUPER::idle (@_, cb => $cb)
@@ -206,10 +209,10 @@ sub condvar {
my %arg = @_;
!exists $arg{cb} or ref $arg{cb}
- or croak "AnyEvent->condvar called with illegal cb argument '$arg{cb}'";
+ or confess "AnyEvent->condvar called with illegal cb argument '$arg{cb}'";
my @cb = exists $arg{cb} ? (cb => wrap delete $arg{cb}) : ();
- croak "AnyEvent->condvar called with unsupported parameter(s) " . join ", ", keys %arg
+ confess "AnyEvent->condvar called with unsupported parameter(s) " . join ", ", keys %arg
if keys %arg;
$class->SUPER::condvar (@cb);
@@ -219,7 +222,7 @@ sub time {
my $class = shift;
@_
- and croak "AnyEvent->time wrongly called with paramaters";
+ and confess "AnyEvent->time wrongly called with paramaters";
$class->SUPER::time (@_)
}
@@ -228,7 +231,7 @@ sub now {
my $class = shift;
@_
- and croak "AnyEvent->now wrongly called with paramaters";
+ and confess "AnyEvent->now wrongly called with paramaters";
$class->SUPER::now (@_)
}
@@ -1009,7 +1009,8 @@ sub verify_hostname($$$) {
my @cert_alt = Net::SSLeay::X509_get_subjectAltNames ($cert);
# rfc2460 - convert to network byte order
- my $ip = AnyEvent::Socket::parse_address $cn;
+ require AnyEvent::Socket;
+ my $ip = AnyEvent::Socket::parse_address ($cn);
my $alt_dns_count;
@@ -1102,7 +1103,7 @@ all...
You can switch off verification. You still get an encrypted connection
that is protected against eavesdropping and injection - you just lose
protection against man in the middle attacks, i.e. somebody else with
-enough abilities to to intercept all traffic can masquerade herself as the
+enough abilities to intercept all traffic can masquerade herself as the
other side.
For many applications, switching off verification is entirely
@@ -1144,7 +1145,7 @@ on what to watch out for.
=head1 BUGS
-To to the abysmal code quality of Net::SSLeay, this module will leak small
+Due to the abysmal code quality of Net::SSLeay, this module will leak small
amounts of memory per TLS connection (currently at least one perl scalar).
=head1 AUTHORS
@@ -472,7 +472,8 @@ when the program exits I<and> all redirected file descriptors have been
exhausted.
The C<$cmd> is either a single string, which is then passed to a shell, or
-an arrayref, which is passed to the C<execvp> function.
+an arrayref, which is passed to the C<execvp> function (the first array
+element is used both for the executable name and argv[0]).
The key-value pairs can be:
@@ -564,7 +565,7 @@ Example: run F<openssl> and create a self-signed certificate and key,
storing them in C<$cert> and C<$key>. When finished, check the exit status
in the callback and print key and certificate.
- my $cv = run_cmd [qw(openssl req
+ my $cv = run_cmd [qw(openssl req
-new -nodes -x509 -days 3650
-newkey rsa:2048 -keyout /dev/fd/3
-batch -subj /CN=AnyEvent
@@ -2,8 +2,8 @@
AnyEvent - the DBI of event loop programming
-EV, Event, Glib, Tk, Perl, Event::Lib, Irssi, rxvt-unicode, IO::Async, Qt,
-FLTK and POE are various supported event loops/environments.
+EV, Event, Glib, Tk, UV, Perl, Event::Lib, Irssi, rxvt-unicode, IO::Async,
+Qt, FLTK and POE are various supported event loops/environments.
=head1 SYNOPSIS
@@ -885,6 +885,7 @@ create watchers. Nothing special needs to be done by the main program.
AnyEvent::Impl::Event based on Event, very stable, few glitches.
AnyEvent::Impl::Glib based on Glib, slow but very stable.
AnyEvent::Impl::Tk based on Tk, very broken.
+ AnyEvent::Impl::UV based on UV, innovated square wheels.
AnyEvent::Impl::EventLib based on Event::Lib, leaks memory and worse.
AnyEvent::Impl::POE based on POE, very slow, some limitations.
AnyEvent::Impl::Irssi used when running within irssi.
@@ -1035,7 +1036,7 @@ asynchronously does something for you and returns some transaction
object or guard to let you cancel the operation. For example,
C<AnyEvent::Socket::tcp_connect>:
- # start a conenction attempt unless one is active
+ # start a connection attempt unless one is active
$self->{connect_guard} ||= AnyEvent::Socket::tcp_connect "www.example.net", 80, sub {
delete $self->{connect_guard};
...
@@ -1249,7 +1250,7 @@ BEGIN {
use Carp ();
-our $VERSION = '7.07';
+our $VERSION = '7.08';
our $MODEL;
our @ISA;
our @REGISTRY;
@@ -1368,6 +1369,7 @@ our @models = (
# everything below here should not be autoloaded
[Event::Lib:: => AnyEvent::Impl::EventLib::], # too buggy
[Tk:: => AnyEvent::Impl::Tk::], # crashes with many handles
+ [UV:: => AnyEvent::Impl::UV::], # switched from libev, added back all bugs imaginable
[Qt:: => AnyEvent::Impl::Qt::], # requires special main program
[POE::Kernel:: => AnyEvent::Impl::POE::], # lasciate ogni speranza
[Wx:: => AnyEvent::Impl::POE::],
@@ -1566,7 +1568,7 @@ package AE;
our $VERSION = $AnyEvent::VERSION;
sub _reset() {
- eval q{
+ eval q{
# fall back to the main API by default - backends and AnyEvent::Base
# implementations can overwrite these.
@@ -2212,7 +2214,7 @@ list.
This variable can effectively be used for denial-of-service attacks
against local programs (e.g. when setuid), although the impact is likely
-small, as the program has to handle conenction and other failures anyways.
+small, as the program has to handle connection and other failures anyways.
Examples: C<PERL_ANYEVENT_PROTOCOLS=ipv4,ipv6> - prefer IPv4 over IPv6,
but support both and try to use both. C<PERL_ANYEVENT_PROTOCOLS=ipv4>
@@ -15,6 +15,7 @@ cat <<EOF
67_tk AnyEvent::Impl::Tk
68_poe AnyEvent::Impl::POE $^W = 0;
69_ev AnyEvent::Impl::EV
+70_uv AnyEvent::Impl::UV
EOF
) | while read base module extra; do
for test in 01 02 03 04 05 07 09; do
@@ -0,0 +1,28 @@
+use AnyEvent;
+
+ BEGIN { $^W = 0 }
+ BEGIN { $ENV{PERL_ANYEVENT_LOOP_TESTS} or ((print qq{1..0 # SKIP PERL_ANYEVENT_LOOP_TESTS not true\n}), exit 0) }
+ BEGIN { eval q{use AnyEvent::Impl::UV;1} or ((print qq{1..0 # SKIP AnyEvent::Impl::UV not loadable\n}), exit 0) }
+
+
+
+$| = 1; print "1..6\n";
+
+print "ok 1\n";
+
+my $cv = AnyEvent->condvar;
+
+print "ok 2\n";
+
+my $timer1 = AnyEvent->timer (after => 0.1, cb => sub { print "ok 5\n"; $cv->broadcast });
+
+print "ok 3\n";
+
+AnyEvent->timer (after => 0.01, cb => sub { print "not ok 5\n" });
+
+print "ok 4\n";
+
+$cv->wait;
+
+print "ok 6\n";
+
@@ -0,0 +1,46 @@
+BEGIN {
+ unless (exists $SIG{USR1}) {
+ print <<EOF;
+1..0 # SKIP Broken perl detected, skipping tests.
+EOF
+ exit 0;
+ }
+}
+
+use AnyEvent;
+
+ BEGIN { $^W = 0 }
+ BEGIN { $ENV{PERL_ANYEVENT_LOOP_TESTS} or ((print qq{1..0 # SKIP PERL_ANYEVENT_LOOP_TESTS not true\n}), exit 0) }
+ BEGIN { eval q{use AnyEvent::Impl::UV;1} or ((print qq{1..0 # SKIP AnyEvent::Impl::UV not loadable\n}), exit 0) }
+
+
+
+$| = 1; print "1..5\n";
+
+print "ok 1\n";
+
+my $cv = AnyEvent->condvar;
+
+my $error = AnyEvent->timer (after => 5, cb => sub {
+ print <<EOF;
+Bail out! No signal caught.
+EOF
+ exit 0;
+});
+
+my $sw = AnyEvent->signal (signal => 'INT', cb => sub {
+ print "ok 3\n";
+ $cv->broadcast;
+});
+
+print "ok 2\n";
+kill 'INT', $$;
+$cv->recv;
+undef $error;
+
+print "ok 4\n";
+
+undef $sw;
+
+print "ok 5\n";
+
@@ -0,0 +1,99 @@
+use POSIX ();
+
+no warnings;
+
+BEGIN {
+ # check for broken perls
+ if ($^O =~ /mswin32/i) {
+ my $ok;
+ local $SIG{CHLD} = sub { $ok = 1 };
+ kill 'CHLD', 0;
+
+ unless ($ok) {
+ print <<EOF;
+1..0 # SKIP Your perl interpreter is badly BROKEN. Child watchers will not work, ever. Try upgrading to a newer perl or a working perl (cygwin's perl is known to work). If that is not an option, you should be able to use the remaining functionality of AnyEvent, but child watchers WILL NOT WORK.
+EOF
+ exit 0;
+ }
+ }
+}
+
+use AnyEvent;
+
+ BEGIN { $^W = 0 }
+ BEGIN { $ENV{PERL_ANYEVENT_LOOP_TESTS} or ((print qq{1..0 # SKIP PERL_ANYEVENT_LOOP_TESTS not true\n}), exit 0) }
+ BEGIN { eval q{use AnyEvent::Impl::UV;1} or ((print qq{1..0 # SKIP AnyEvent::Impl::UV not loadable\n}), exit 0) }
+
+
+
+$| = 1; print "1..50\n";
+
+$AnyEvent::MAX_SIGNAL_LATENCY = 0.2;
+
+for my $it ("", 1, 2, 3, 4) {
+ print "ok ${it}1\n";
+
+ AnyEvent::detect; # force-load event model
+
+ my $pid = fork;
+
+ defined $pid or die "unable to fork";
+
+ # work around Tk bug until it has been fixed.
+ #my $timer = AnyEvent->timer (after => 2, cb => sub { });
+
+ my $cv = AnyEvent->condvar;
+
+ unless ($pid) {
+ print "ok ${it}2 # child $$\n";
+
+ # POE hits a race condition when the child dies too quickly
+ # because it checks for child exit before installing the signal handler.
+ # seen in version 1.352 - earlier versions had the same bug, but
+ # polled for child exits regularly, so only caused a delay.
+ sleep 1 if $AnyEvent::MODEL eq "AnyEvent::Impl::POE";
+
+ POSIX::_exit 3;
+ }
+ my $w = AnyEvent->child (pid => $pid, cb => sub {
+ print $pid == $_[0] ? "" : "not ", "ok ${it}3\ # $pid == $_[0]\n";
+ print 3 == ($_[1] >> 8) ? "" : "not ", "ok ${it}4 # 3 == $_[1] >> 8 ($_[1])\n";
+ $cv->broadcast;
+ });
+
+ $cv->recv;
+
+ my $pid2 = fork || do {
+ sleep 1 if $AnyEvent::MODEL eq "AnyEvent::Impl::POE";
+ POSIX::_exit 7;
+ };
+
+ my $cv2 = AnyEvent->condvar;
+
+ # Glib is the only model that doesn't support pid == 0
+ my $pid0 = $AnyEvent::MODEL eq "AnyEvent::Impl::Glib" ? $pid2 : 0;
+
+ my $w2 = AnyEvent->child (pid => $pid0, cb => sub {
+ print $pid2 == $_[0] ? "" : "not ", "ok ${it}5 # $pid2 == $_[0]\n";
+ print 7 == ($_[1] >> 8) ? "" : "not ", "ok ${it}6 # 7 == $_[1] >> 8 ($_[1])\n";
+ $cv2->broadcast;
+ });
+
+ my $error = AnyEvent->timer (after => 5, cb => sub {
+ print <<EOF;
+Bail out! No child exit detected. This is either a bug in AnyEvent or a bug in your Perl (mostly some windows distributions suffer from that): child watchers might not work properly on this platform. You can force installation of this module if you do not rely on child watchers, or you could upgrade to a working version of Perl for your platform.\n";
+EOF
+ exit 0;
+ });
+
+ $cv2->recv;
+
+ print "ok ${it}7\n";
+ print "ok ${it}8\n";
+ print "ok ${it}9\n";
+ print "ok ", $it*10+10, "\n";
+}
+
+
+
+
@@ -0,0 +1,99 @@
+use AnyEvent;
+
+ BEGIN { $^W = 0 }
+ BEGIN { $ENV{PERL_ANYEVENT_LOOP_TESTS} or ((print qq{1..0 # SKIP PERL_ANYEVENT_LOOP_TESTS not true\n}), exit 0) }
+ BEGIN { eval q{use AnyEvent::Impl::UV;1} or ((print qq{1..0 # SKIP AnyEvent::Impl::UV not loadable\n}), exit 0) }
+
+
+
+$| = 1; print "1..28\n";
+
+print "ok 1\n";
+
+{
+ my $cv = AnyEvent->condvar;
+
+ $cv->cb (sub {
+ print $_[0]->ready ? "" : "not ", "ok 4\n";
+
+ my $x = $_[0]->recv;
+ print $x == 7 ? "" : "not ", "ok 5 # $x == 7\n";
+
+ my @x = $_[0]->recv;
+ print $x[1] == 5 ? "" : "not ", "ok 6 # $x[1] == 5\n";
+
+ my $y = $cv->recv;
+ print $y == 7 ? "" : "not ", "ok 7 # $x == 7\n";
+ });
+
+ my $t = AnyEvent->timer (after => 0, cb => sub {
+ print "ok 3\n";
+ $cv->send (7, 5);
+ });
+
+ print "ok 2\n";
+ $cv->recv;
+ print "ok 8\n";
+
+ my @x = $cv->recv;
+ print $x[1] == 5 ? "" : "not ", "ok 9 # $x[1] == 5\n";
+}
+
+{
+ my $cv = AnyEvent->condvar;
+
+ $cv->cb (sub {
+ print $_[0]->ready ? "" : "not ", "ok 12\n";
+
+ my $x = eval { $_[0]->recv };
+ print !defined $x ? "" : "not ", "ok 13\n";
+ print $@ =~ /^kill/ ? "" : "not ", "ok 14 # $@\n";
+ });
+
+ my $t = AnyEvent->timer (after => 0, cb => sub {
+ print "ok 11\n";
+ $cv->croak ("kill");
+ print "ok 15\n";
+ $cv->send (8, 6, 4);
+ print "ok 16\n";
+ });
+
+ print "ok 10\n";
+ my @x = eval { $cv->recv };
+ print !@x ? "" : "not ", "ok 17 # @x\n";
+ print $@ =~ /^kill / ? "" : "not ", "ok 18 # $@\n";
+}
+
+{
+ my $cv = AnyEvent->condvar;
+
+ print "ok 19\n";
+ my $t = AnyEvent->timer (after => 0, cb => $cv);
+
+ print "ok 20\n";
+ $cv->recv;
+ print "ok 21\n";
+}
+
+{
+ my $cv = AE::cv {
+ print +($_[0]->recv)[0] == 6 ? "" : "not ", "ok 27\n";
+ };
+
+ print "ok 22\n";
+
+ $cv->begin (sub {
+ print "ok 26\n";
+ $_[0](6);
+ });
+
+ print "ok 23\n";
+ $cv->begin;
+ print "ok 24\n";
+ $cv->end;
+ print "ok 25\n";
+ $cv->end;
+
+ print "ok 28\n";
+}
+
@@ -0,0 +1,37 @@
+# we avoid complicated tests here because some systems will
+# not have working DNS
+
+use AnyEvent;
+
+ BEGIN { $^W = 0 }
+ BEGIN { $ENV{PERL_ANYEVENT_LOOP_TESTS} or ((print qq{1..0 # SKIP PERL_ANYEVENT_LOOP_TESTS not true\n}), exit 0) }
+ BEGIN { eval q{use AnyEvent::Impl::UV;1} or ((print qq{1..0 # SKIP AnyEvent::Impl::UV not loadable\n}), exit 0) }
+
+
+use AnyEvent::DNS;
+
+$| = 1; print "1..5\n";
+
+print "ok 1\n";
+
+AnyEvent::DNS::resolver;
+
+print "ok 2\n";
+
+# make sure we timeout faster
+AnyEvent::DNS::resolver->{timeout} = [0.5];
+AnyEvent::DNS::resolver->_compile;
+
+print "ok 3\n";
+
+my $cv = AnyEvent->condvar;
+
+AnyEvent::DNS::a "www.google.de", sub {
+ print "ok 4 # www.google.de => @_\n";
+ $cv->send;
+};
+
+$cv->recv;
+
+print "ok 5\n";
+
@@ -0,0 +1,85 @@
+use AnyEvent;
+use AnyEvent::Util;
+
+ BEGIN { $^W = 0 }
+ BEGIN { $ENV{PERL_ANYEVENT_LOOP_TESTS} or ((print qq{1..0 # SKIP PERL_ANYEVENT_LOOP_TESTS not true\n}), exit 0) }
+ BEGIN { eval q{use AnyEvent::Impl::UV;1} or ((print qq{1..0 # SKIP AnyEvent::Impl::UV not loadable\n}), exit 0) }
+
+
+
+$| = 1; print "1..18\n";
+
+print "ok 1\n";
+
+my ($a, $b) = AnyEvent::Util::portable_socketpair;
+
+print $a && $b ? "" : "not ", "ok 2 # $a,$b\n";
+
+my ($cv, $t, $ra, $wa, $rb, $wb);
+
+$rb = AnyEvent->io (fh => $b, poll => "r", cb => sub {
+ print "ok 6\n";
+ sysread $b, my $buf, 1;
+ print "ok 7\n";
+ $wb = AnyEvent->io (fh => $b, poll => "w", cb => sub {
+ print "ok 8\n";
+ undef $wb;
+ syswrite $b, "1";
+ });
+});
+
+print "ok 3\n";
+
+{ my $cv = AnyEvent->condvar; $t = AnyEvent->timer (after => 0.05, cb => sub { $cv->send }); $cv->recv }
+
+print "ok 4\n";
+
+$wa = AnyEvent->io (fh => $a, poll => "w", cb => sub {
+ syswrite $a, "0";
+ undef $wa;
+ print "ok 5\n";
+});
+
+$ra = AnyEvent->io (fh => $a, poll => "r", cb => sub {
+ sysread $a, my $buf, 1;
+ print "ok 9\n";
+ $cv->send;
+});
+
+$cv = AnyEvent->condvar; $cv->recv;
+
+print "ok 10\n";
+
+$rb = AnyEvent->io (fh => fileno $b, poll => "r", cb => sub {
+ print "ok 14\n";
+ sysread $b, my $buf, 1;
+ print "ok 15\n";
+ $wb = AnyEvent->io (fh => fileno $b, poll => "w", cb => sub {
+ print "ok 16\n";
+ undef $wb;
+ syswrite $b, "1";
+ });
+});
+
+print "ok 11\n";
+
+{ my $cv = AnyEvent->condvar; $t = AnyEvent->timer (after => 0.05, cb => sub { $cv->send }); $cv->recv }
+
+print "ok 12\n";
+
+$wa = AnyEvent->io (fh => fileno $a, poll => "w", cb => sub {
+ syswrite $a, "0";
+ undef $wa;
+ print "ok 13\n";
+});
+
+$ra = AnyEvent->io (fh => $a, poll => "r", cb => sub {
+ sysread $a, my $buf, 1;
+ print "ok 17\n";
+ $cv->send;
+});
+
+$cv = AnyEvent->condvar; $cv->recv;
+
+print "ok 18\n";
+
@@ -0,0 +1,179 @@
+BEGIN {
+ # check for broken perls
+ if ($^O =~ /mswin32/i) {
+ my $ok;
+ local $SIG{CHLD} = sub { $ok = 1 };
+ kill 'CHLD', 0;
+
+ unless ($ok) {
+ print <<EOF;
+1..0 # SKIP Your perl interpreter is badly BROKEN. Child watchers will not work, ever. Try upgrading to a newer perl or a working perl (cygwin's perl is known to work). If that is not an option, you should be able to use the remaining functionality of AnyEvent, but child watchers WILL NOT WORK.
+EOF
+ exit 0;
+ }
+ }
+}
+
+$^W = 0; # 5.8.6 bugs
+
+use AnyEvent;
+use AnyEvent::Util;
+
+ BEGIN { $^W = 0 }
+ BEGIN { $ENV{PERL_ANYEVENT_LOOP_TESTS} or ((print qq{1..0 # SKIP PERL_ANYEVENT_LOOP_TESTS not true\n}), exit 0) }
+ BEGIN { eval q{use AnyEvent::Impl::UV;1} or ((print qq{1..0 # SKIP AnyEvent::Impl::UV not loadable\n}), exit 0) }
+
+
+
+$| = 1; print "1..15\n";
+
+print "ok 1\n";
+
+$AnyEvent::MAX_SIGNAL_LATENCY = 0.05;
+
+my ($a, $b) = AnyEvent::Util::portable_socketpair;
+
+# I/O write
+{
+ my $cv = AE::cv;
+ my $wt = AE::timer 1, 0, $cv;
+ my $s = 0;
+
+ $cv->begin; my $wa = AE::io $a, 1, sub { $cv->end; $s |= 1 };
+ $cv->begin; my $wb = AE::io $a, 1, sub { $cv->end; $s |= 2 };
+
+ $cv->recv;
+
+ print $s == 3 ? "" : "not ", "ok 2 # $s\n";
+}
+
+# I/O read
+{
+ my $cv = AE::cv;
+ my $wt = AE::timer 0.01, 0, $cv;
+ my $s = 0;
+
+ my $wa = AE::io $a, 0, sub { $cv->end; $s |= 1 };
+ my $wb = AE::io $a, 0, sub { $cv->end; $s |= 2 };
+
+ $cv->recv;
+
+ print $s == 0 ? "" : "not ", "ok 3 # $s\n";
+
+ syswrite $b, "x";
+
+ $cv = AE::cv;
+ $wt = AE::timer 1, 0, $cv;
+
+ $s = 0;
+ $cv->begin;
+ $cv->begin;
+ $cv->recv;
+
+ print $s == 3 ? "" : "not ", "ok 4 # $s\n";
+
+ sysread $a, my $dummy, 1;
+
+ $cv = AE::cv;
+ $wt = AE::timer 0.01, 0, $cv;
+
+ $s = 0;
+ $cv->recv;
+
+ print $s == 0 ? "" : "not ", "ok 5 # $s\n";
+}
+
+# signal
+{
+ my $cv = AE::cv;
+ my $wt = AE::timer 0.01, 0, $cv;
+ my $s = 0;
+
+ $cv->begin; my $wa = AE::signal INT => sub { $cv->end; $s |= 1 };
+ $cv->begin; my $wb = AE::signal INT => sub { $cv->end; $s |= 2 };
+
+ $cv->recv;
+
+ print $s == 0 ? "" : "not ", "ok 6 # $s\n";
+
+ kill INT => $$;
+
+ $cv = AE::cv;
+ $wt = AE::timer 0.2, 0, $cv; # maybe OS X needs more time here? or maybe some buggy arm kernel?
+
+ $s = 0;
+ $cv->recv;
+
+ print $s == 3 ? "" : "not ", "ok 7 # $s\n";
+
+ $cv = AE::cv;
+ $wt = AE::timer 0.01, 0, $cv;
+
+ $s = 0;
+ $cv->recv;
+
+ print $s == 0 ? "" : "not ", "ok 8 # $s\n";
+}
+
+# child
+{
+ my $cv = AE::cv;
+ my $wt = AE::timer 0.01, 0, $cv;
+ my $s = 0;
+
+ my $pid = fork;
+
+ unless ($pid) {
+ sleep 2;
+ exit 1;
+ }
+
+ my ($apid, $bpid, $astatus, $bstatus);
+
+ $cv->begin; my $wa = AE::child $pid, sub { ($apid, $astatus) = @_; $cv->end; $s |= 1 };
+ $cv->begin; my $wb = AE::child $pid, sub { ($bpid, $bstatus) = @_; $cv->end; $s |= 2 };
+
+ $cv->recv;
+
+ print $s == 0 ? "" : "not ", "ok 9 # $s\n";
+
+ kill 9, $pid;
+
+ $cv = AE::cv;
+ $wt = AE::timer 0.2, 0, $cv; # cygwin needs ages for this
+
+ $s = 0;
+ $cv->recv;
+
+ print $s == 3 ? "" : "not ", "ok 10 # $s\n";
+ print $apid == $pid && $bpid == $pid ? "" : "not ", "ok 11 # $apid == $bpid == $pid\n";
+ print $astatus == 9 && $bstatus == 9 ? "" : "not ", "ok 12 # $astatus == $bstatus == 9\n";
+
+ $cv = AE::cv;
+ $wt = AE::timer 0.01, 0, $cv;
+
+ $s = 0;
+ $cv->recv;
+
+ print $s == 0 ? "" : "not ", "ok 13 # $s\n";
+}
+
+# timers (don't laugh, some event loops are more broken...)
+{
+ my $cv = AE::cv;
+ my $wt = AE::timer 1, 0, $cv;
+ my $s = 0;
+
+ $cv->begin; my $wa = AE::timer 0 , 0, sub { $cv->end; $s |= 1 };
+ $cv->begin; my $wb = AE::timer 0 , 0, sub { $cv->end; $s |= 2 };
+ $cv->begin; my $wc = AE::timer 0.01, 0, sub { $cv->end; $s |= 4 };
+
+ $cv->recv;
+
+ print $s == 7 ? "" : "not ", "ok 14 # $s\n";
+}
+
+print "ok 15\n";
+
+exit 0;
+