=head1 NAME
Coro::Select - a (slow but coro-aware) replacement for CORE::select
=head1 SYNOPSIS
use Coro::Select; # replace select globally (be careful, see below)
use Core::Select 'select'; # only in this module
use Coro::Select (); # use Coro::Select::select
=head1 DESCRIPTION
This module tries to create a fully working replacement for perl's
C<select> built-in, using C<AnyEvent> watchers to do the job, so other
threads can run in parallel to any select user. As many libraries that
only have a blocking API do not use global variables and often use select
(or IO::Select), this effectively makes most such libraries "somewhat"
non-blocking w.r.t. other threads.
This implementation works fastest when only very few bits are set in the
fd set(s).
To be effective globally, this module must be C<use>'d before any other
module that uses C<select>, so it should generally be the first module
C<use>'d in the main program. Note that overriding C<select> globally
might actually cause problems, as some C<AnyEvent> backends use C<select>
themselves, and asking AnyEvent to use Coro::Select, which in turn asks
AnyEvent will not quite work.
You can also invoke it from the commandline as C<perl -MCoro::Select>.
To override select only for a single module (e.g. C<Net::DBus::Reactor>),
use a code fragment like this to load it:
{
package Net::DBus::Reactor;
use Coro::Select qw(select);
use Net::DBus::Reactor;
}
Some modules (notably L<POE::Loop::Select>) directly call
C<CORE::select>. For these modules, we need to patch the opcode table by
sandwiching it between calls to C<Coro::Select::patch_pp_sselect> and
C<Coro::Select::unpatch_pp_sselect>:
BEGIN {
use Coro::Select ();
Coro::Select::patch_pp_sselect;
require evil_poe_module_using_CORE::SELECT;
Coro::Select::unpatch_pp_sselect;
}
=over 4
=cut
package Coro::Select;
use common::sense;
use Errno;
use Coro ();
use Coro::State ();
use AnyEvent 4.800001 ();
use Coro::AnyEvent ();
use base Exporter::;
our $VERSION = 6.57;
our @EXPORT_OK = "select";
sub import {
my $pkg = shift;
if (@_) {
$pkg->export (scalar caller 0, @_);
} else {
$pkg->export ("CORE::GLOBAL", "select");
}
}
sub select(;*$$$) {
if (@_ == 0) {
return CORE::select
} elsif (@_ == 1) {
return CORE::select $_[0]
} elsif (defined $_[3] && !$_[3]) {
return CORE::select $_[0], $_[1], $_[2], $_[3]
} else {
my $nfound = 0;
my @w;
my $wakeup = Coro::rouse_cb;
# AnyEvent does not do 'e', so replace it by 'r'
for ([0, 0], [1, 1], [2, 0]) {
my ($i, $poll) = @$_;
if (defined $_[$i]) {
my $rvec = \$_[$i];
# we parse the bitmask by first expanding it into
# a string of bits
for (unpack "b*", $$rvec) {
# and then repeatedly matching a regex against it
while (/1/g) {
my $fd = (pos) - 1;
push @w,
AE::io $fd, $poll, sub {
(vec $$rvec, $fd, 1) = 1;
++$nfound;
$wakeup->();
};
}
}
$$rvec ^= $$rvec; # clear all bits
}
}
push @w,
AE::timer $_[3], 0, $wakeup
if defined $_[3];
Coro::rouse_wait;
return $nfound
}
}
1;
=back
=head1 BUGS
For performance reasons, Coro::Select's select function might not
properly detect bad file descriptors (but relying on EBADF is inherently
non-portable).
=head1 SEE ALSO
L<Coro::LWP>.
=head1 AUTHOR/SUPPORT/CONTACT
Marc A. Lehmann <schmorp@schmorp.de>
http://software.schmorp.de/pkg/Coro.html
=cut