line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
# You may distribute under the terms of either the GNU General Public License |
2
|
|
|
|
|
|
|
# or the Artistic License (the same terms as Perl itself) |
3
|
|
|
|
|
|
|
# |
4
|
|
|
|
|
|
|
# (C) Paul Evans, 2007-2020 -- leonerd@leonerd.org.uk |
5
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
package IO::Async::Loop::Select; |
7
|
|
|
|
|
|
|
|
8
|
15
|
|
|
15
|
|
72872
|
use strict; |
|
15
|
|
|
|
|
49
|
|
|
15
|
|
|
|
|
481
|
|
9
|
15
|
|
|
15
|
|
78
|
use warnings; |
|
15
|
|
|
|
|
30
|
|
|
15
|
|
|
|
|
674
|
|
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
our $VERSION = '0.801'; |
12
|
15
|
|
|
15
|
|
83
|
use constant API_VERSION => '0.49'; |
|
15
|
|
|
|
|
30
|
|
|
15
|
|
|
|
|
1438
|
|
13
|
|
|
|
|
|
|
|
14
|
15
|
|
|
15
|
|
270
|
use base qw( IO::Async::Loop ); |
|
15
|
|
|
|
|
41
|
|
|
15
|
|
|
|
|
10887
|
|
15
|
|
|
|
|
|
|
|
16
|
15
|
|
|
15
|
|
125
|
use IO::Async::OS; |
|
15
|
|
|
|
|
32
|
|
|
15
|
|
|
|
|
404
|
|
17
|
|
|
|
|
|
|
|
18
|
15
|
|
|
15
|
|
88
|
use Carp; |
|
15
|
|
|
|
|
32
|
|
|
15
|
|
|
|
|
1030
|
|
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
# select() on most platforms claims that ISREG files are always read- and |
21
|
|
|
|
|
|
|
# write-ready, but not on MSWin32. We need to fake this |
22
|
15
|
|
|
15
|
|
111
|
use constant FAKE_ISREG_READY => IO::Async::OS->HAVE_FAKE_ISREG_READY; |
|
15
|
|
|
|
|
34
|
|
|
15
|
|
|
|
|
1012
|
|
23
|
|
|
|
|
|
|
# select() on most platforms indicates write-ready when connect() fails, but |
24
|
|
|
|
|
|
|
# not on MSWin32. Have to pull from evec in that case |
25
|
15
|
|
|
15
|
|
92
|
use constant SELECT_CONNECT_EVEC => IO::Async::OS->HAVE_SELECT_CONNECT_EVEC; |
|
15
|
|
|
|
|
33
|
|
|
15
|
|
|
|
|
800
|
|
26
|
|
|
|
|
|
|
|
27
|
15
|
|
|
15
|
|
90
|
use constant _CAN_WATCHDOG => 1; |
|
15
|
|
|
|
|
23
|
|
|
15
|
|
|
|
|
736
|
|
28
|
15
|
|
|
15
|
|
92
|
use constant WATCHDOG_ENABLE => IO::Async::Loop->WATCHDOG_ENABLE; |
|
15
|
|
|
|
|
32
|
|
|
15
|
|
|
|
|
14028
|
|
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
=head1 NAME |
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
C - use L with C |
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
=head1 SYNOPSIS |
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
Normally an instance of this class would not be directly constructed by a |
37
|
|
|
|
|
|
|
program. It may however, be useful for runinng L with an existing |
38
|
|
|
|
|
|
|
program already using a C |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
use IO::Async::Loop::Select; |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
my $loop = IO::Async::Loop::Select->new; |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
$loop->add( ... ); |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
while(1) { |
47
|
|
|
|
|
|
|
my ( $rvec, $wvec, $evec ) = ('') x 3; |
48
|
|
|
|
|
|
|
my $timeout; |
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
$loop->pre_select( \$rvec, \$wvec, \$evec, \$timeout ); |
51
|
|
|
|
|
|
|
... |
52
|
|
|
|
|
|
|
my $ret = select( $rvec, $wvec, $evec, $timeout ); |
53
|
|
|
|
|
|
|
... |
54
|
|
|
|
|
|
|
$loop->post_select( $rvec, $evec, $wvec ); |
55
|
|
|
|
|
|
|
} |
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
=head1 DESCRIPTION |
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
This subclass of L uses the C |
60
|
|
|
|
|
|
|
read-ready and write-ready tests. |
61
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
To integrate with an existing C |
63
|
|
|
|
|
|
|
C and C can be called immediately before and |
64
|
|
|
|
|
|
|
after a C |
65
|
|
|
|
|
|
|
exceptional-state bitvectors are set by the C method, and tested |
66
|
|
|
|
|
|
|
by the C method to pick which event callbacks to invoke. |
67
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
=cut |
69
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
=head1 CONSTRUCTOR |
71
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
=cut |
73
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
=head2 new |
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
$loop = IO::Async::Loop::Select->new |
77
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
This function returns a new instance of a C object. |
79
|
|
|
|
|
|
|
It takes no special arguments. |
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
=cut |
82
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
sub new |
84
|
|
|
|
|
|
|
{ |
85
|
14
|
|
|
14
|
1
|
124
|
my $class = shift; |
86
|
|
|
|
|
|
|
|
87
|
14
|
|
|
|
|
110
|
my $self = $class->__new( @_ ); |
88
|
|
|
|
|
|
|
|
89
|
14
|
|
|
|
|
33
|
$self->{rvec} = ''; |
90
|
14
|
|
|
|
|
28
|
$self->{wvec} = ''; |
91
|
14
|
|
|
|
|
28
|
$self->{evec} = ''; |
92
|
|
|
|
|
|
|
|
93
|
14
|
|
|
|
|
41
|
$self->{avec} = ''; # Bitvector of handles always to claim are ready |
94
|
|
|
|
|
|
|
|
95
|
14
|
|
|
|
|
47
|
return $self; |
96
|
|
|
|
|
|
|
} |
97
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
=head1 METHODS |
99
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
=cut |
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
=head2 pre_select |
103
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
$loop->pre_select( \$readvec, \$writevec, \$exceptvec, \$timeout ) |
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
This method prepares the bitvectors for a C |
107
|
|
|
|
|
|
|
that the Loop is interested in. It will also adjust the C<$timeout> value if |
108
|
|
|
|
|
|
|
appropriate, reducing it if the next event timeout the Loop requires is sooner |
109
|
|
|
|
|
|
|
than the current value. |
110
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
=over 8 |
112
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
=item \$readvec |
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
=item \$writevec |
116
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
=item \$exceptvec |
118
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
Scalar references to the reading, writing and exception bitvectors |
120
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
=item \$timeout |
122
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
Scalar reference to the timeout value |
124
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
=back |
126
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
=cut |
128
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
sub pre_select |
130
|
|
|
|
|
|
|
{ |
131
|
83
|
|
|
83
|
1
|
328
|
my $self = shift; |
132
|
83
|
|
|
|
|
222
|
my ( $readref, $writeref, $exceptref, $timeref ) = @_; |
133
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
# BITWISE operations |
135
|
83
|
|
|
|
|
420
|
$$readref |= $self->{rvec}; |
136
|
83
|
|
|
|
|
236
|
$$writeref |= $self->{wvec}; |
137
|
83
|
|
|
|
|
195
|
$$exceptref |= $self->{evec}; |
138
|
|
|
|
|
|
|
|
139
|
83
|
|
|
|
|
653
|
$self->_adjust_timeout( $timeref ); |
140
|
|
|
|
|
|
|
|
141
|
83
|
|
|
|
|
150
|
$$timeref = 0 if FAKE_ISREG_READY and length $self->{avec}; |
142
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
# Round up to nearest millisecond |
144
|
83
|
100
|
|
|
|
269
|
if( $$timeref ) { |
145
|
71
|
|
|
|
|
231
|
my $mils = $$timeref * 1000; |
146
|
71
|
|
|
|
|
198
|
my $fraction = $mils - int $mils; |
147
|
71
|
100
|
|
|
|
245
|
$$timeref += ( 1 - $fraction ) / 1000 if $fraction; |
148
|
|
|
|
|
|
|
} |
149
|
|
|
|
|
|
|
|
150
|
83
|
|
|
|
|
200
|
return; |
151
|
|
|
|
|
|
|
} |
152
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
=head2 post_select |
154
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
$loop->post_select( $readvec, $writevec, $exceptvec ) |
156
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
This method checks the returned bitvectors from a C |
158
|
|
|
|
|
|
|
any of the callbacks that are appropriate. |
159
|
|
|
|
|
|
|
|
160
|
|
|
|
|
|
|
=over 8 |
161
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
=item $readvec |
163
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
=item $writevec |
165
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
=item $exceptvec |
167
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
Scalars containing the read-ready, write-ready and exception bitvectors |
169
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
=back |
171
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
=cut |
173
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
sub post_select |
175
|
|
|
|
|
|
|
{ |
176
|
81
|
|
|
81
|
1
|
3511176
|
my $self = shift; |
177
|
81
|
|
|
|
|
354
|
my ( $readvec, $writevec, $exceptvec ) = @_; |
178
|
|
|
|
|
|
|
|
179
|
81
|
|
|
|
|
241
|
my $iowatches = $self->{iowatches}; |
180
|
|
|
|
|
|
|
|
181
|
81
|
|
|
|
|
171
|
my $count = 0; |
182
|
|
|
|
|
|
|
|
183
|
81
|
|
|
|
|
147
|
alarm( IO::Async::Loop->WATCHDOG_INTERVAL ) if WATCHDOG_ENABLE; |
184
|
|
|
|
|
|
|
|
185
|
81
|
|
|
|
|
494
|
foreach my $fd ( keys %$iowatches ) { |
186
|
58
|
100
|
|
|
|
248
|
my $watch = $iowatches->{$fd} or next; |
187
|
|
|
|
|
|
|
|
188
|
57
|
|
|
|
|
717
|
my $fileno = $watch->[0]->fileno; |
189
|
|
|
|
|
|
|
|
190
|
57
|
100
|
100
|
|
|
851
|
if( vec( $readvec, $fileno, 1 ) or |
191
|
|
|
|
|
|
|
FAKE_ISREG_READY and vec( $self->{avec}, $fileno, 1 ) and vec( $self->{rvec}, $fileno, 1 ) ) { |
192
|
30
|
50
|
|
|
|
240
|
$count++, $watch->[1]->() if defined $watch->[1]; |
193
|
|
|
|
|
|
|
} |
194
|
|
|
|
|
|
|
|
195
|
57
|
50
|
100
|
|
|
650
|
if( vec( $writevec, $fileno, 1 ) or |
|
|
|
100
|
|
|
|
|
196
|
|
|
|
|
|
|
SELECT_CONNECT_EVEC and vec( $exceptvec, $fileno, 1 ) or |
197
|
|
|
|
|
|
|
FAKE_ISREG_READY and vec( $self->{avec}, $fileno, 1 ) and vec( $self->{wvec}, $fileno, 1 ) ) { |
198
|
5
|
100
|
|
|
|
23
|
$count++, $watch->[2]->() if defined $watch->[2]; |
199
|
|
|
|
|
|
|
} |
200
|
|
|
|
|
|
|
} |
201
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
# Since we have no way to know if the timeout occurred, we'll have to |
203
|
|
|
|
|
|
|
# attempt to fire any waiting timeout events anyway |
204
|
|
|
|
|
|
|
|
205
|
81
|
|
|
|
|
483
|
$self->_manage_queues; |
206
|
|
|
|
|
|
|
|
207
|
81
|
|
|
|
|
397
|
alarm( 0 ) if WATCHDOG_ENABLE; |
208
|
|
|
|
|
|
|
} |
209
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
sub is_running |
211
|
|
|
|
|
|
|
{ |
212
|
1
|
|
|
1
|
0
|
3
|
my $self = shift; |
213
|
1
|
|
|
|
|
9
|
return $self->{running}; |
214
|
|
|
|
|
|
|
} |
215
|
|
|
|
|
|
|
|
216
|
|
|
|
|
|
|
=head2 loop_once |
217
|
|
|
|
|
|
|
|
218
|
|
|
|
|
|
|
$count = $loop->loop_once( $timeout ) |
219
|
|
|
|
|
|
|
|
220
|
|
|
|
|
|
|
This method calls the C method to prepare the bitvectors for a |
221
|
|
|
|
|
|
|
C |
222
|
|
|
|
|
|
|
result. It returns the total number of callbacks invoked by the |
223
|
|
|
|
|
|
|
C method, or C if the underlying C |
224
|
|
|
|
|
|
|
returned an error. |
225
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
=cut |
227
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
sub loop_once |
229
|
|
|
|
|
|
|
{ |
230
|
77
|
|
|
77
|
1
|
203
|
my $self = shift; |
231
|
77
|
|
|
|
|
373
|
my ( $timeout ) = @_; |
232
|
|
|
|
|
|
|
|
233
|
77
|
|
|
|
|
383
|
my ( $rvec, $wvec, $evec ) = ('') x 3; |
234
|
|
|
|
|
|
|
|
235
|
77
|
|
|
|
|
639
|
$self->pre_select( \$rvec, \$wvec, \$evec, \$timeout ); |
236
|
|
|
|
|
|
|
|
237
|
77
|
|
|
|
|
462
|
$self->pre_wait; |
238
|
77
|
|
|
|
|
22710764
|
my $ret = select( $rvec, $wvec, $evec, $timeout ); |
239
|
77
|
|
|
|
|
2177
|
$self->post_wait; |
240
|
|
|
|
|
|
|
|
241
|
77
|
100
|
|
|
|
2312
|
if( $ret < 0 ) { |
242
|
|
|
|
|
|
|
# r/w/e vec can't be trusted |
243
|
12
|
|
|
|
|
56
|
$rvec = $wvec = $evec = ''; |
244
|
|
|
|
|
|
|
} |
245
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
{ |
247
|
77
|
|
|
|
|
238
|
local $!; |
|
77
|
|
|
|
|
1259
|
|
248
|
77
|
|
|
|
|
470
|
$self->post_select( $rvec, $wvec, $evec ); |
249
|
|
|
|
|
|
|
} |
250
|
|
|
|
|
|
|
|
251
|
77
|
|
|
|
|
364
|
return $ret; |
252
|
|
|
|
|
|
|
} |
253
|
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
sub watch_io |
255
|
|
|
|
|
|
|
{ |
256
|
18
|
|
|
18
|
1
|
2911
|
my $self = shift; |
257
|
18
|
|
|
|
|
83
|
my %params = @_; |
258
|
|
|
|
|
|
|
|
259
|
18
|
|
|
|
|
180
|
$self->__watch_io( %params ); |
260
|
|
|
|
|
|
|
|
261
|
18
|
|
|
|
|
103
|
my $fileno = $params{handle}->fileno; |
262
|
|
|
|
|
|
|
|
263
|
18
|
100
|
|
|
|
185
|
vec( $self->{rvec}, $fileno, 1 ) = 1 if $params{on_read_ready}; |
264
|
18
|
100
|
|
|
|
83
|
vec( $self->{wvec}, $fileno, 1 ) = 1 if $params{on_write_ready}; |
265
|
|
|
|
|
|
|
|
266
|
|
|
|
|
|
|
# MSWin32 does not indicate writeready for connect() errors, HUPs, etc |
267
|
|
|
|
|
|
|
# but it does indicate exceptional |
268
|
18
|
|
|
|
|
36
|
vec( $self->{evec}, $fileno, 1 ) = 1 if SELECT_CONNECT_EVEC and $params{on_write_ready}; |
269
|
|
|
|
|
|
|
|
270
|
18
|
|
|
|
|
62
|
vec( $self->{avec}, $fileno, 1 ) = 1 if FAKE_ISREG_READY and stat( $params{handle} ) and -f _; |
271
|
|
|
|
|
|
|
} |
272
|
|
|
|
|
|
|
|
273
|
|
|
|
|
|
|
sub unwatch_io |
274
|
|
|
|
|
|
|
{ |
275
|
12
|
|
|
12
|
1
|
1115
|
my $self = shift; |
276
|
12
|
|
|
|
|
61
|
my %params = @_; |
277
|
|
|
|
|
|
|
|
278
|
12
|
|
|
|
|
73
|
$self->__unwatch_io( %params ); |
279
|
|
|
|
|
|
|
|
280
|
12
|
|
|
|
|
42
|
my $fileno = $params{handle}->fileno; |
281
|
|
|
|
|
|
|
|
282
|
12
|
100
|
|
|
|
115
|
vec( $self->{rvec}, $fileno, 1 ) = 0 if $params{on_read_ready}; |
283
|
12
|
100
|
|
|
|
48
|
vec( $self->{wvec}, $fileno, 1 ) = 0 if $params{on_write_ready}; |
284
|
|
|
|
|
|
|
|
285
|
12
|
|
|
|
|
22
|
vec( $self->{evec}, $fileno, 1 ) = 0 if SELECT_CONNECT_EVEC and $params{on_write_ready}; |
286
|
|
|
|
|
|
|
|
287
|
12
|
|
|
|
|
21
|
vec( $self->{avec}, $fileno, 1 ) = 0 if FAKE_ISREG_READY and stat( $params{handle} ) and -f _; |
288
|
|
|
|
|
|
|
|
289
|
|
|
|
|
|
|
# vec will grow a bit vector as needed, but never shrink it. We'll trim |
290
|
|
|
|
|
|
|
# trailing null bytes |
291
|
12
|
|
|
|
|
299
|
$_ =~s/\0+\z// for $self->{rvec}, $self->{wvec}, $self->{evec}, $self->{avec}; |
292
|
|
|
|
|
|
|
} |
293
|
|
|
|
|
|
|
|
294
|
|
|
|
|
|
|
=head1 SEE ALSO |
295
|
|
|
|
|
|
|
|
296
|
|
|
|
|
|
|
=over 4 |
297
|
|
|
|
|
|
|
|
298
|
|
|
|
|
|
|
=item * |
299
|
|
|
|
|
|
|
|
300
|
|
|
|
|
|
|
L - OO interface to select system call |
301
|
|
|
|
|
|
|
|
302
|
|
|
|
|
|
|
=back |
303
|
|
|
|
|
|
|
|
304
|
|
|
|
|
|
|
=head1 AUTHOR |
305
|
|
|
|
|
|
|
|
306
|
|
|
|
|
|
|
Paul Evans |
307
|
|
|
|
|
|
|
|
308
|
|
|
|
|
|
|
=cut |
309
|
|
|
|
|
|
|
|
310
|
|
|
|
|
|
|
0x55AA; |