File: Select.pm

package info (click to toggle)
libcoro-perl 6.570-4
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 1,144 kB
  • sloc: ansic: 2,560; perl: 2,122; makefile: 14
file content (151 lines) | stat: -rw-r--r-- 3,782 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
=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