| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
# $Id: Select.pm,v 1.18 2010/01/01 14:52:17 dk Exp $ |
|
2
|
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
package IO::Lambda::Loop::Select; |
|
4
|
27
|
|
|
27
|
|
146
|
use strict; |
|
|
27
|
|
|
|
|
42
|
|
|
|
27
|
|
|
|
|
700
|
|
|
5
|
27
|
|
|
27
|
|
129
|
use warnings; |
|
|
27
|
|
|
|
|
47
|
|
|
|
27
|
|
|
|
|
895
|
|
|
6
|
27
|
|
|
27
|
|
137
|
use Errno qw(EINTR EAGAIN); |
|
|
27
|
|
|
|
|
38
|
|
|
|
27
|
|
|
|
|
3833
|
|
|
7
|
27
|
|
|
27
|
|
157
|
use IO::Lambda qw(:constants); |
|
|
27
|
|
|
|
|
54
|
|
|
|
27
|
|
|
|
|
4852
|
|
|
8
|
27
|
|
|
27
|
|
137
|
use Time::HiRes qw(time); |
|
|
27
|
|
|
|
|
51
|
|
|
|
27
|
|
|
|
|
223
|
|
|
9
|
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
IO::Lambda::Loop::default('Select'); |
|
11
|
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
our $DEBUG = $IO::Lambda::DEBUG{select} || 0; |
|
13
|
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
# IO::Select::select doesn't distinguish between select returning 0 and -1, don't have |
|
15
|
|
|
|
|
|
|
# time to fix that. I'll just use a plain select instead, it'll be faster also. |
|
16
|
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
sub new |
|
18
|
|
|
|
|
|
|
{ |
|
19
|
27
|
|
|
27
|
1
|
83
|
my $self = bless {} , shift; |
|
20
|
27
|
|
|
|
|
217
|
$self-> {$_} = '' for qw(read write exc); |
|
21
|
27
|
|
|
|
|
65
|
$self-> {items} = {}; |
|
22
|
27
|
|
|
|
|
64
|
$self-> {timers} = []; |
|
23
|
27
|
|
|
|
|
180
|
return $self; |
|
24
|
|
|
|
|
|
|
} |
|
25
|
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
sub empty |
|
27
|
|
|
|
|
|
|
{ |
|
28
|
487807
|
|
|
487807
|
1
|
599639
|
my $self = shift; |
|
29
|
|
|
|
|
|
|
return ( |
|
30
|
487807
|
|
|
|
|
789069
|
@{$self->{timers}} + |
|
31
|
487807
|
100
|
|
|
|
487231
|
keys(%{$self-> {items}}) |
|
|
487807
|
|
|
|
|
1829823
|
|
|
32
|
|
|
|
|
|
|
) ? 0 : 1; |
|
33
|
|
|
|
|
|
|
} |
|
34
|
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
sub yield |
|
36
|
|
|
|
|
|
|
{ |
|
37
|
250
|
|
|
250
|
1
|
593
|
my ( $self, $nonblocking ) = @_; |
|
38
|
|
|
|
|
|
|
|
|
39
|
250
|
50
|
|
|
|
697
|
return if $self-> empty; |
|
40
|
|
|
|
|
|
|
|
|
41
|
250
|
|
|
|
|
420
|
my $t; |
|
42
|
250
|
50
|
|
|
|
801
|
$t = 0 if $nonblocking; |
|
43
|
|
|
|
|
|
|
|
|
44
|
250
|
|
|
|
|
458
|
my ($min,$max) = ( 0, -1); |
|
45
|
250
|
|
|
|
|
902
|
my $ct = time; |
|
46
|
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
# timers |
|
48
|
250
|
|
|
|
|
378
|
for ( @{$self-> {timers}}) { |
|
|
250
|
|
|
|
|
734
|
|
|
49
|
136
|
100
|
100
|
|
|
1284
|
$t = $_->[WATCH_DEADLINE] |
|
|
|
|
33
|
|
|
|
|
|
50
|
|
|
|
|
|
|
if defined $_->[WATCH_DEADLINE] and |
|
51
|
|
|
|
|
|
|
(!defined($t) or $t > $_-> [WATCH_DEADLINE]); |
|
52
|
|
|
|
|
|
|
} |
|
53
|
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
# handles |
|
55
|
250
|
|
|
|
|
444
|
my ( $R, $W, $E) = @{$self}{qw(read write exc)}; |
|
|
250
|
|
|
|
|
890
|
|
|
56
|
|
|
|
|
|
|
|
|
57
|
250
|
|
|
|
|
605
|
while ( my ( $fileno, $bucket) = each %{ $self-> {items}} ) { |
|
|
567
|
|
|
|
|
2058
|
|
|
58
|
317
|
|
|
|
|
601
|
for ( @$bucket) { |
|
59
|
317
|
100
|
100
|
|
|
1033
|
$t = $_->[WATCH_DEADLINE] |
|
|
|
|
66
|
|
|
|
|
|
60
|
|
|
|
|
|
|
if defined $_->[WATCH_DEADLINE] and |
|
61
|
|
|
|
|
|
|
(!defined($t) or $t > $_-> [WATCH_DEADLINE]); |
|
62
|
|
|
|
|
|
|
} |
|
63
|
317
|
50
|
|
|
|
768
|
warn "select: fileno $fileno\n" if $DEBUG; |
|
64
|
317
|
100
|
|
|
|
1078
|
$max = $fileno if $max < $fileno; |
|
65
|
317
|
50
|
33
|
|
|
2262
|
$min = $fileno if !defined($min) or $min > $fileno; |
|
66
|
|
|
|
|
|
|
} |
|
67
|
250
|
100
|
|
|
|
758
|
if ( defined $t) { |
|
|
|
50
|
|
|
|
|
|
|
68
|
109
|
|
|
|
|
248
|
$t -= $ct; |
|
69
|
109
|
100
|
|
|
|
376
|
$t = 0 if $t < 0; |
|
70
|
109
|
50
|
|
|
|
337
|
warn "select: timeout=$t\n" if $DEBUG; |
|
71
|
|
|
|
|
|
|
} elsif ( $DEBUG) { |
|
72
|
0
|
|
|
|
|
0
|
warn "select: no timeout\n"; |
|
73
|
|
|
|
|
|
|
} |
|
74
|
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
# do select |
|
76
|
250
|
|
|
|
|
5772747
|
my $n = select( $R, $W, $E, $t); |
|
77
|
250
|
50
|
|
|
|
1183
|
warn "select: $n handles ready\n" if $DEBUG; |
|
78
|
250
|
100
|
|
|
|
740
|
if ( $n < 0) { |
|
79
|
1
|
50
|
33
|
|
|
41
|
if ( $! == EINTR or $! == EAGAIN) { |
|
80
|
|
|
|
|
|
|
# ignore |
|
81
|
1
|
50
|
|
|
|
8
|
warn "select: $!\n" if $DEBUG; |
|
82
|
|
|
|
|
|
|
} else { |
|
83
|
|
|
|
|
|
|
# find out the rogue handles |
|
84
|
0
|
0
|
|
|
|
0
|
if ( $DEBUG > 1) { |
|
85
|
0
|
|
|
|
|
0
|
my $h = $R | $W | $E; |
|
86
|
0
|
|
|
|
|
0
|
for ( my $i = 0; $i < length($h); $i++) { |
|
87
|
0
|
|
|
|
|
0
|
my $v = ''; |
|
88
|
0
|
|
|
|
|
0
|
for ( my $j = 0; $j < 8; $j++) { |
|
89
|
0
|
|
|
|
|
0
|
my $fd = $i * 8 + $j; |
|
90
|
0
|
0
|
|
|
|
0
|
next unless vec($h,$fd,1); |
|
91
|
0
|
|
|
|
|
0
|
vec($v,$fd,1) = 1; |
|
92
|
0
|
0
|
|
|
|
0
|
next if select($v,$v,$v,0) >= 0; |
|
93
|
0
|
|
|
|
|
0
|
warn "select: bad handle #$fd\n"; |
|
94
|
|
|
|
|
|
|
} |
|
95
|
|
|
|
|
|
|
} |
|
96
|
|
|
|
|
|
|
} |
|
97
|
0
|
|
|
|
|
0
|
die "select() error:$!:$^E"; |
|
98
|
|
|
|
|
|
|
} |
|
99
|
|
|
|
|
|
|
} |
|
100
|
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
# expired timers |
|
102
|
250
|
|
|
|
|
709
|
my ( @kill, @expired); |
|
103
|
|
|
|
|
|
|
|
|
104
|
250
|
|
|
|
|
719
|
$t = $self-> {timers}; |
|
105
|
|
|
|
|
|
|
@$t = grep { |
|
106
|
250
|
100
|
|
|
|
823
|
($$_[WATCH_DEADLINE] <= $ct) ? do { |
|
|
136
|
|
|
|
|
1007
|
|
|
107
|
47
|
|
|
|
|
158
|
push @expired, $_; |
|
108
|
47
|
|
|
|
|
177
|
0; |
|
109
|
|
|
|
|
|
|
} : 1; |
|
110
|
|
|
|
|
|
|
} @$t; |
|
111
|
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
# handles |
|
113
|
250
|
100
|
|
|
|
709
|
if ( $n > 0) { |
|
114
|
|
|
|
|
|
|
# process selected handles |
|
115
|
165
|
|
100
|
|
|
1527
|
for ( my $i = $min; $i <= $max && $n > 0; $i++) { |
|
116
|
1750
|
|
|
|
|
3590
|
my $what = |
|
117
|
|
|
|
|
|
|
vec( $R, $i, 1) * IO_READ + |
|
118
|
|
|
|
|
|
|
vec( $W, $i, 1) * IO_WRITE + |
|
119
|
|
|
|
|
|
|
vec( $E, $i, 1) * IO_EXCEPTION |
|
120
|
|
|
|
|
|
|
; |
|
121
|
1750
|
100
|
|
|
|
9407
|
next unless $what; |
|
122
|
|
|
|
|
|
|
|
|
123
|
212
|
|
|
|
|
467
|
my $bucket = $self-> {items}-> {$i}; |
|
124
|
|
|
|
|
|
|
@$bucket = grep { |
|
125
|
212
|
50
|
|
|
|
496
|
($$_[WATCH_IO_FLAGS] & $what) ? do { |
|
|
212
|
|
|
|
|
751
|
|
|
126
|
212
|
|
|
|
|
370
|
$$_[WATCH_IO_FLAGS] &= $what; |
|
127
|
212
|
|
|
|
|
350
|
push @expired, $_; |
|
128
|
212
|
|
|
|
|
729
|
0; |
|
129
|
|
|
|
|
|
|
} : 1; |
|
130
|
|
|
|
|
|
|
} @$bucket; |
|
131
|
212
|
50
|
|
|
|
746
|
delete $self-> {items}->{$i} unless @$bucket; |
|
132
|
212
|
|
|
|
|
1264
|
$n--; |
|
133
|
|
|
|
|
|
|
} |
|
134
|
|
|
|
|
|
|
} else { |
|
135
|
|
|
|
|
|
|
# else process timeouts |
|
136
|
85
|
|
|
|
|
242
|
my @kill; |
|
137
|
85
|
|
|
|
|
219
|
while ( my ( $fileno, $bucket) = each %{ $self-> {items}}) { |
|
|
93
|
|
|
|
|
605
|
|
|
138
|
|
|
|
|
|
|
@$bucket = grep { |
|
139
|
8
|
|
|
|
|
27
|
( |
|
140
|
|
|
|
|
|
|
defined($_->[WATCH_DEADLINE]) && |
|
141
|
|
|
|
|
|
|
$_->[WATCH_DEADLINE] <= $ct |
|
142
|
8
|
100
|
100
|
|
|
80
|
) ? do { |
|
143
|
1
|
|
|
|
|
5
|
$$_[WATCH_IO_FLAGS] = 0; |
|
144
|
1
|
|
|
|
|
4
|
push @expired, $_; |
|
145
|
1
|
|
|
|
|
6
|
0; |
|
146
|
|
|
|
|
|
|
} : 1; |
|
147
|
|
|
|
|
|
|
} @$bucket; |
|
148
|
8
|
100
|
|
|
|
51
|
push @kill, $fileno unless @$bucket; |
|
149
|
|
|
|
|
|
|
} |
|
150
|
85
|
|
|
|
|
176
|
delete @{$self->{items}}{@kill}; |
|
|
85
|
|
|
|
|
281
|
|
|
151
|
|
|
|
|
|
|
} |
|
152
|
250
|
|
|
|
|
1066
|
$self-> rebuild_vectors; |
|
153
|
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
# call them |
|
155
|
250
|
|
|
|
|
1904
|
$$_[WATCH_OBJ]-> io_handler( $_) for @expired; |
|
156
|
|
|
|
|
|
|
} |
|
157
|
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
sub watch |
|
159
|
|
|
|
|
|
|
{ |
|
160
|
218
|
|
|
218
|
1
|
368
|
my ( $self, $rec) = @_; |
|
161
|
218
|
|
|
|
|
602
|
my $fileno = fileno $rec->[WATCH_IO_HANDLE]; |
|
162
|
218
|
50
|
|
|
|
576
|
die "Invalid filehandle" unless defined $fileno; |
|
163
|
218
|
|
|
|
|
320
|
my $flags = $rec->[WATCH_IO_FLAGS]; |
|
164
|
|
|
|
|
|
|
|
|
165
|
218
|
100
|
|
|
|
1370
|
vec($self-> {read}, $fileno, 1) = 1 if $flags & IO_READ; |
|
166
|
218
|
100
|
|
|
|
681
|
vec($self-> {write}, $fileno, 1) = 1 if $flags & IO_WRITE; |
|
167
|
218
|
100
|
|
|
|
739
|
vec($self-> {exc}, $fileno, 1) = 1 if $flags & IO_EXCEPTION; |
|
168
|
|
|
|
|
|
|
|
|
169
|
218
|
|
|
|
|
287
|
push @{$self-> {items}-> {$fileno}}, $rec; |
|
|
218
|
|
|
|
|
1293
|
|
|
170
|
|
|
|
|
|
|
} |
|
171
|
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
sub after |
|
173
|
|
|
|
|
|
|
{ |
|
174
|
58
|
|
|
58
|
1
|
170
|
my ( $self, $rec) = @_; |
|
175
|
58
|
|
|
|
|
98
|
push @{$self-> {timers}}, $rec; |
|
|
58
|
|
|
|
|
240
|
|
|
176
|
|
|
|
|
|
|
} |
|
177
|
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
sub remove |
|
179
|
|
|
|
|
|
|
{ |
|
180
|
46
|
|
|
46
|
1
|
153
|
my ($self, $obj) = @_; |
|
181
|
|
|
|
|
|
|
|
|
182
|
46
|
|
|
|
|
168
|
@{$self-> {timers}} = grep { |
|
183
|
7
|
50
|
|
|
|
105
|
defined($_->[WATCH_OBJ]) and $_->[WATCH_OBJ] != $obj |
|
184
|
46
|
|
|
|
|
134
|
} @{$self-> {timers}}; |
|
|
46
|
|
|
|
|
170
|
|
|
185
|
|
|
|
|
|
|
|
|
186
|
46
|
|
|
|
|
120
|
my @kill; |
|
187
|
46
|
|
|
|
|
109
|
while ( my ( $fileno, $bucket) = each %{$self->{items}}) { |
|
|
71
|
|
|
|
|
499
|
|
|
188
|
25
|
50
|
|
|
|
77
|
@$bucket = grep { defined($_->[WATCH_OBJ]) and $_->[WATCH_OBJ] != $obj } @$bucket; |
|
|
25
|
|
|
|
|
309
|
|
|
189
|
25
|
100
|
|
|
|
161
|
next if @$bucket; |
|
190
|
5
|
|
|
|
|
27
|
push @kill, $fileno; |
|
191
|
|
|
|
|
|
|
} |
|
192
|
46
|
|
|
|
|
126
|
delete @{$self->{items}}{@kill}; |
|
|
46
|
|
|
|
|
179
|
|
|
193
|
|
|
|
|
|
|
|
|
194
|
46
|
|
|
|
|
228
|
$self-> rebuild_vectors; |
|
195
|
|
|
|
|
|
|
} |
|
196
|
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
sub remove_event |
|
198
|
|
|
|
|
|
|
{ |
|
199
|
10
|
|
|
10
|
1
|
30
|
my ($self, $rec) = @_; |
|
200
|
|
|
|
|
|
|
|
|
201
|
10
|
|
|
|
|
22
|
@{$self-> {timers}} = grep { $_ != $rec } @{$self-> {timers}}; |
|
|
10
|
|
|
|
|
35
|
|
|
|
7
|
|
|
|
|
36
|
|
|
|
10
|
|
|
|
|
193
|
|
|
202
|
|
|
|
|
|
|
|
|
203
|
10
|
|
|
|
|
25
|
my @kill; |
|
204
|
10
|
|
|
|
|
31
|
while ( my ( $fileno, $bucket) = each %{$self->{items}}) { |
|
|
12
|
|
|
|
|
84
|
|
|
205
|
2
|
|
|
|
|
17
|
@$bucket = grep { $_ != $rec } @$bucket; |
|
|
2
|
|
|
|
|
8
|
|
|
206
|
2
|
50
|
|
|
|
11
|
next if @$bucket; |
|
207
|
0
|
|
|
|
|
0
|
push @kill, $fileno; |
|
208
|
|
|
|
|
|
|
} |
|
209
|
10
|
|
|
|
|
27
|
delete @{$self->{items}}{@kill}; |
|
|
10
|
|
|
|
|
38
|
|
|
210
|
|
|
|
|
|
|
|
|
211
|
10
|
|
|
|
|
39
|
$self-> rebuild_vectors; |
|
212
|
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
} |
|
214
|
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
sub rebuild_vectors |
|
216
|
|
|
|
|
|
|
{ |
|
217
|
306
|
|
|
306
|
0
|
640
|
my $self = $_[0]; |
|
218
|
306
|
|
|
|
|
2511
|
$self-> {$_} = '' for qw(read write exc); |
|
219
|
306
|
|
|
|
|
685
|
my $r = \ $self-> {read}; |
|
220
|
306
|
|
|
|
|
694
|
my $w = \ $self-> {write}; |
|
221
|
306
|
|
|
|
|
658
|
my $e = \ $self-> {exc}; |
|
222
|
306
|
|
|
|
|
633
|
while ( my ( $fileno, $bucket) = each %{$self->{items}}) { |
|
|
432
|
|
|
|
|
2334
|
|
|
223
|
126
|
|
|
|
|
322
|
for my $flags ( map { $_-> [WATCH_IO_FLAGS] } @$bucket) { |
|
|
126
|
|
|
|
|
439
|
|
|
224
|
126
|
100
|
|
|
|
629
|
vec($$r, $fileno, 1) = 1 if $flags & IO_READ; |
|
225
|
126
|
100
|
|
|
|
430
|
vec($$w, $fileno, 1) = 1 if $flags & IO_WRITE; |
|
226
|
126
|
50
|
|
|
|
1288
|
vec($$e, $fileno, 1) = 1 if $flags & IO_EXCEPTION; |
|
227
|
|
|
|
|
|
|
} |
|
228
|
|
|
|
|
|
|
} |
|
229
|
|
|
|
|
|
|
} |
|
230
|
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
1; |
|
232
|
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
__DATA__ |