| 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, 2026 -- leonerd@leonerd.org.uk |
|
5
|
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
package Future::IO::Impl::Ppoll 0.05; |
|
7
|
|
|
|
|
|
|
|
|
8
|
12
|
|
|
12
|
|
2959772
|
use v5.20; |
|
|
12
|
|
|
|
|
46
|
|
|
9
|
12
|
|
|
12
|
|
73
|
use warnings; |
|
|
12
|
|
|
|
|
28
|
|
|
|
12
|
|
|
|
|
626
|
|
|
10
|
12
|
|
|
12
|
|
68
|
use base qw( Future::IO::ImplBase ); |
|
|
12
|
|
|
|
|
20
|
|
|
|
12
|
|
|
|
|
2328
|
|
|
11
|
|
|
|
|
|
|
|
|
12
|
12
|
|
|
12
|
|
57540
|
use feature qw( postderef signatures ); |
|
|
12
|
|
|
|
|
28
|
|
|
|
12
|
|
|
|
|
1720
|
|
|
13
|
12
|
|
|
12
|
|
87
|
no warnings qw( experimental::postderef experimental::signatures ); |
|
|
12
|
|
|
|
|
19
|
|
|
|
12
|
|
|
|
|
622
|
|
|
14
|
|
|
|
|
|
|
|
|
15
|
12
|
|
|
12
|
|
81
|
use Carp; |
|
|
12
|
|
|
|
|
28
|
|
|
|
12
|
|
|
|
|
1131
|
|
|
16
|
|
|
|
|
|
|
our @CARP_NOT = qw( Future::IO::Impl::Ppoll::_Future ); |
|
17
|
|
|
|
|
|
|
|
|
18
|
12
|
|
|
12
|
|
6337
|
use IO::Ppoll 0.14 qw( POLLIN POLLOUT POLLPRI POLLHUP POLLERR POLLNVAL ); |
|
|
12
|
|
|
|
|
117762
|
|
|
|
12
|
|
|
|
|
1232
|
|
|
19
|
12
|
|
|
12
|
|
135
|
use POSIX qw( SIG_BLOCK sigprocmask ); |
|
|
12
|
|
|
|
|
39
|
|
|
|
12
|
|
|
|
|
78
|
|
|
20
|
12
|
|
|
12
|
|
20941
|
use Struct::Dumb qw( readonly_struct ); |
|
|
12
|
|
|
|
|
23
|
|
|
|
12
|
|
|
|
|
100
|
|
|
21
|
12
|
|
|
12
|
|
823
|
use Time::HiRes qw( time ); |
|
|
12
|
|
|
|
|
35
|
|
|
|
12
|
|
|
|
|
106
|
|
|
22
|
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
BEGIN { |
|
24
|
12
|
50
|
|
12
|
|
2816
|
if( $^V ge v5.36 ) { |
|
25
|
12
|
|
|
|
|
183
|
builtin->import(qw( refaddr )); |
|
26
|
12
|
50
|
|
|
|
1396
|
warnings->unimport(qw( experimental::builtin )) if $^V lt v5.40; |
|
27
|
|
|
|
|
|
|
} |
|
28
|
|
|
|
|
|
|
else { |
|
29
|
0
|
|
|
|
|
0
|
require Scalar::Util; |
|
30
|
0
|
|
|
|
|
0
|
Scalar::Util->import(qw( refaddr )); |
|
31
|
|
|
|
|
|
|
} |
|
32
|
|
|
|
|
|
|
} |
|
33
|
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
BEGIN { |
|
35
|
12
|
|
|
12
|
|
189
|
Future::IO->VERSION( '0.20' ); |
|
36
|
|
|
|
|
|
|
# Just check for sanity |
|
37
|
|
|
|
|
|
|
IO::Ppoll->$_ == Future::IO->$_ or die "This implementation relies on the Future::IO $_ constant being the same as system\n" |
|
38
|
12
|
|
50
|
|
|
18923
|
for qw( POLLIN POLLOUT POLLPRI POLLHUP POLLERR POLLNVAL ); |
|
39
|
|
|
|
|
|
|
} |
|
40
|
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
__PACKAGE__->APPLY; |
|
42
|
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
=head1 NAME |
|
44
|
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
C - implement C using C |
|
46
|
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
=head1 DESCRIPTION |
|
48
|
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
=for highlighter language=perl |
|
50
|
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
This module provides an implementation for L which uses the |
|
52
|
|
|
|
|
|
|
C system call, via L. |
|
53
|
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
There are no additional methods to use in this module; it simply has to be |
|
55
|
|
|
|
|
|
|
loaded, and it will provide the C implementation methods: |
|
56
|
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
use Future::IO; |
|
58
|
|
|
|
|
|
|
use Future::IO::Impl::Ppoll; |
|
59
|
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
my $f = Future::IO->sleep(5); |
|
61
|
|
|
|
|
|
|
... |
|
62
|
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
Note that the C method will take over the operation of C<$SIG{CHLD}>, |
|
64
|
|
|
|
|
|
|
and will print a warning if it discovers some other code has already set it. |
|
65
|
|
|
|
|
|
|
Make sure not to otherwise override this signal handler in your program, or |
|
66
|
|
|
|
|
|
|
else the C futures will stop working. |
|
67
|
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
=cut |
|
69
|
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
readonly_struct Poller => [qw( events f )]; |
|
71
|
|
|
|
|
|
|
my %fh_by_refaddr; |
|
72
|
|
|
|
|
|
|
my %pollers_by_refaddr; |
|
73
|
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
readonly_struct Alarm => [qw( time f )]; |
|
75
|
|
|
|
|
|
|
my @alarms; |
|
76
|
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
my $ppoll; |
|
78
|
164
|
|
66
|
164
|
0
|
267
|
sub ppoll () { $ppoll //= IO::Ppoll->new } |
|
|
164
|
|
|
|
|
231
|
|
|
|
164
|
|
|
|
|
1009
|
|
|
79
|
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
sub _update_poll ( $fh ) |
|
81
|
106
|
|
|
106
|
|
175
|
{ |
|
|
106
|
|
|
|
|
171
|
|
|
|
106
|
|
|
|
|
197
|
|
|
82
|
106
|
|
|
|
|
188
|
my $refaddr = refaddr $fh; |
|
83
|
106
|
50
|
|
|
|
530
|
defined $fh->fileno or |
|
84
|
|
|
|
|
|
|
carp "Filehandle $fh lost its fileno (was closed?) during poll"; |
|
85
|
|
|
|
|
|
|
|
|
86
|
106
|
|
|
|
|
763
|
my $mask = 0; |
|
87
|
106
|
|
50
|
|
|
2189
|
$mask |= $_->events for ( $pollers_by_refaddr{$refaddr} // [] )->@*; |
|
88
|
|
|
|
|
|
|
|
|
89
|
106
|
|
|
|
|
940
|
ppoll()->mask( $fh => $mask ); |
|
90
|
106
|
100
|
|
|
|
2109
|
if( $mask ) { |
|
91
|
70
|
|
|
|
|
210
|
$fh_by_refaddr{$refaddr} = $fh; |
|
92
|
|
|
|
|
|
|
} |
|
93
|
|
|
|
|
|
|
else { |
|
94
|
36
|
|
|
|
|
125
|
delete $fh_by_refaddr{$refaddr}; |
|
95
|
36
|
|
|
|
|
143
|
delete $pollers_by_refaddr{$refaddr}; |
|
96
|
|
|
|
|
|
|
} |
|
97
|
|
|
|
|
|
|
} |
|
98
|
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
our $RECURSION; |
|
100
|
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
sub _tick ( $ ) |
|
102
|
58
|
|
|
58
|
|
693
|
{ |
|
|
58
|
|
|
|
|
97
|
|
|
103
|
58
|
50
|
|
|
|
191
|
carp "Future::IO::Impl::Ppoll is not reentrant; strange things may happen" if $RECURSION; |
|
104
|
58
|
|
|
|
|
151
|
local $RECURSION = 1; |
|
105
|
|
|
|
|
|
|
|
|
106
|
58
|
|
|
|
|
149
|
my $ppoll = ppoll(); |
|
107
|
|
|
|
|
|
|
|
|
108
|
58
|
|
|
|
|
400
|
my $timeout = undef; |
|
109
|
58
|
100
|
|
|
|
175
|
if( @alarms ) { |
|
110
|
|
|
|
|
|
|
# These are sorted by time order, so head is soonest |
|
111
|
5
|
|
|
|
|
179
|
$timeout = $alarms[0]->time - time(); |
|
112
|
5
|
50
|
|
|
|
54
|
$timeout = 0 if $timeout < 0; |
|
113
|
|
|
|
|
|
|
} |
|
114
|
|
|
|
|
|
|
|
|
115
|
58
|
|
|
|
|
1410
|
$ppoll->poll( $timeout ); |
|
116
|
|
|
|
|
|
|
|
|
117
|
58
|
|
|
|
|
2077094
|
foreach my $refaddr ( keys %fh_by_refaddr ) { |
|
118
|
61
|
|
|
|
|
228
|
my $fh = $fh_by_refaddr{$refaddr}; |
|
119
|
|
|
|
|
|
|
# If the filehandle has no fileno, that means it was closed. It was |
|
120
|
|
|
|
|
|
|
# definitely invalid |
|
121
|
61
|
50
|
|
|
|
221
|
my $revents = ( defined $fh->fileno ) ? $ppoll->events( $fh ) : POLLNVAL |
|
|
|
100
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
or next; |
|
123
|
|
|
|
|
|
|
|
|
124
|
52
|
50
|
|
|
|
1023
|
my $pollers = $pollers_by_refaddr{$refaddr} or next; |
|
125
|
|
|
|
|
|
|
# TODO: if nobody cared, maybe we should remove it? |
|
126
|
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
# Find the next poller which cares about at least one of these events |
|
128
|
52
|
|
|
|
|
186
|
foreach my $idx ( 0 .. $#$pollers ) { |
|
129
|
55
|
100
|
|
|
|
1764
|
my $want_revents = $revents & ( $pollers->[$idx]->events | POLLHUP|POLLERR|POLLNVAL ) |
|
130
|
|
|
|
|
|
|
or next; |
|
131
|
|
|
|
|
|
|
|
|
132
|
52
|
|
|
|
|
529
|
my ( $poller ) = splice @$pollers, $idx, 1, (); |
|
133
|
|
|
|
|
|
|
|
|
134
|
52
|
50
|
33
|
|
|
511
|
$poller and $poller->f and $poller->f->done( $want_revents ); |
|
135
|
52
|
|
|
|
|
8533
|
last; |
|
136
|
|
|
|
|
|
|
} |
|
137
|
|
|
|
|
|
|
|
|
138
|
52
|
|
|
|
|
140
|
_update_poll( $fh ); |
|
139
|
|
|
|
|
|
|
} |
|
140
|
|
|
|
|
|
|
|
|
141
|
58
|
|
|
|
|
593
|
my $now = time(); |
|
142
|
58
|
|
100
|
|
|
716
|
while( @alarms and $alarms[0]->time <= $now ) { |
|
143
|
5
|
|
|
|
|
208
|
( shift @alarms )->f->done; |
|
144
|
|
|
|
|
|
|
} |
|
145
|
|
|
|
|
|
|
} |
|
146
|
|
|
|
|
|
|
|
|
147
|
6
|
|
|
|
|
14
|
sub alarm ( $class, $time ) |
|
148
|
6
|
|
|
6
|
1
|
899
|
{ |
|
|
6
|
|
|
|
|
11
|
|
|
|
6
|
|
|
|
|
35
|
|
|
149
|
6
|
|
|
|
|
46
|
my $f = Future::IO::Impl::Ppoll::_Future->new; |
|
150
|
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
# TODO: Binary search |
|
152
|
6
|
|
|
|
|
67
|
my $idx = 0; |
|
153
|
6
|
|
66
|
|
|
93
|
$idx++ while $idx < @alarms and $alarms[$idx]->time < $time; |
|
154
|
|
|
|
|
|
|
|
|
155
|
6
|
|
|
|
|
49
|
splice @alarms, $idx, 0, Alarm( $time, $f ); |
|
156
|
|
|
|
|
|
|
|
|
157
|
1
|
|
|
1
|
|
553
|
$f->on_cancel( sub ( $self ) { |
|
|
1
|
|
|
|
|
16
|
|
|
|
1
|
|
|
|
|
3
|
|
|
158
|
1
|
|
|
|
|
2
|
my $idx = 0; |
|
159
|
1
|
|
33
|
|
|
46
|
$idx++ while $idx < @alarms and $alarms[$idx]->f != $self; |
|
160
|
|
|
|
|
|
|
|
|
161
|
1
|
|
|
|
|
18
|
splice @alarms, $idx, 1, (); |
|
162
|
6
|
|
|
|
|
447
|
} ); |
|
163
|
|
|
|
|
|
|
|
|
164
|
6
|
|
|
|
|
197
|
return $f; |
|
165
|
|
|
|
|
|
|
} |
|
166
|
|
|
|
|
|
|
|
|
167
|
5
|
|
|
|
|
13
|
sub sleep ( $class, $secs ) |
|
168
|
5
|
|
|
5
|
1
|
195155
|
{ |
|
|
5
|
|
|
|
|
10
|
|
|
|
5
|
|
|
|
|
9
|
|
|
169
|
5
|
|
|
|
|
48
|
$class->alarm( time() + $secs ); |
|
170
|
|
|
|
|
|
|
} |
|
171
|
|
|
|
|
|
|
|
|
172
|
54
|
|
|
|
|
143
|
sub poll ( $, $fh, $events ) |
|
173
|
54
|
|
|
54
|
0
|
1946923
|
{ |
|
|
54
|
|
|
|
|
142
|
|
|
|
54
|
|
|
|
|
91
|
|
|
174
|
54
|
50
|
|
|
|
180
|
defined $fh or |
|
175
|
|
|
|
|
|
|
croak "Expected a defined filehandle for ->poll"; |
|
176
|
|
|
|
|
|
|
|
|
177
|
54
|
|
|
|
|
117
|
my $refaddr = refaddr $fh; |
|
178
|
|
|
|
|
|
|
|
|
179
|
54
|
|
100
|
|
|
357
|
my $pollers = $pollers_by_refaddr{$refaddr} //= []; |
|
180
|
|
|
|
|
|
|
|
|
181
|
54
|
|
|
|
|
434
|
my $f = Future::IO::Impl::Ppoll::_Future->new; |
|
182
|
54
|
|
|
|
|
604
|
my $poller = Poller( $events, $f ); |
|
183
|
|
|
|
|
|
|
|
|
184
|
54
|
|
|
|
|
3508
|
push @$pollers, $poller; |
|
185
|
|
|
|
|
|
|
|
|
186
|
54
|
|
|
|
|
196
|
_update_poll( $fh ); |
|
187
|
54
|
|
|
|
|
518
|
return $f; |
|
188
|
|
|
|
|
|
|
} |
|
189
|
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
my $captured_sigchld; |
|
191
|
|
|
|
|
|
|
my %waitpid_futures; |
|
192
|
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
sub waitpid ( $, $pid ) |
|
194
|
3
|
|
|
3
|
0
|
568714
|
{ |
|
|
3
|
|
|
|
|
41
|
|
|
|
3
|
|
|
|
|
14
|
|
|
195
|
3
|
100
|
|
|
|
90
|
unless( $captured_sigchld ) { |
|
196
|
2
|
50
|
33
|
|
|
154
|
$SIG{CHLD} and $SIG{CHLD} ne "IGNORE" and |
|
197
|
|
|
|
|
|
|
warn "Future::IO::Impl::Ppoll is replacing \$SIG{CHLD}"; |
|
198
|
|
|
|
|
|
|
|
|
199
|
3
|
|
|
3
|
|
18
|
$SIG{CHLD} = sub ( $ ) { |
|
|
3
|
|
|
|
|
6
|
|
|
200
|
3
|
|
|
|
|
27
|
foreach my $pid ( keys %waitpid_futures ) { |
|
201
|
3
|
50
|
|
|
|
127
|
next unless waitpid( $pid, POSIX::WNOHANG ) > 0; |
|
202
|
3
|
|
|
|
|
30
|
my $wstatus = $?; |
|
203
|
|
|
|
|
|
|
|
|
204
|
3
|
|
|
|
|
13
|
my $fs = delete $waitpid_futures{$pid}; |
|
205
|
3
|
|
|
|
|
95
|
$_->done( $wstatus ) for @$fs; |
|
206
|
|
|
|
|
|
|
} |
|
207
|
2
|
|
|
|
|
156
|
}; |
|
208
|
|
|
|
|
|
|
|
|
209
|
2
|
|
|
|
|
14
|
$captured_sigchld = 1; |
|
210
|
|
|
|
|
|
|
|
|
211
|
2
|
|
|
|
|
160
|
sigprocmask( SIG_BLOCK, POSIX::SigSet->new( POSIX::SIGCHLD ) ); |
|
212
|
|
|
|
|
|
|
# SIGCHLD is now blocked but will be atomically unblocked by the ppoll() |
|
213
|
|
|
|
|
|
|
# operation |
|
214
|
|
|
|
|
|
|
} |
|
215
|
|
|
|
|
|
|
|
|
216
|
3
|
|
|
|
|
359
|
my $f = Future::IO::Impl::Ppoll::_Future->new; |
|
217
|
|
|
|
|
|
|
|
|
218
|
3
|
50
|
|
|
|
279
|
if( waitpid( $pid, POSIX::WNOHANG ) > 0 ) { |
|
219
|
0
|
|
|
|
|
0
|
my $wstatus = $?; |
|
220
|
0
|
|
|
|
|
0
|
$f->done( $wstatus ); |
|
221
|
0
|
|
|
|
|
0
|
return $f; |
|
222
|
|
|
|
|
|
|
} |
|
223
|
|
|
|
|
|
|
|
|
224
|
3
|
|
|
|
|
124
|
push $waitpid_futures{$pid}->@*, $f; |
|
225
|
|
|
|
|
|
|
|
|
226
|
3
|
|
|
|
|
29
|
return $f; |
|
227
|
|
|
|
|
|
|
} |
|
228
|
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
package Future::IO::Impl::Ppoll::_Future { |
|
230
|
12
|
|
|
12
|
|
94
|
use base qw( Future ); |
|
|
12
|
|
|
|
|
20
|
|
|
|
12
|
|
|
|
|
2989
|
|
|
231
|
|
|
|
|
|
|
|
|
232
|
|
|
|
|
|
|
sub await ( $self ) |
|
233
|
50
|
|
|
50
|
|
10861
|
{ |
|
|
50
|
|
|
|
|
132
|
|
|
|
50
|
|
|
|
|
102
|
|
|
234
|
50
|
|
|
|
|
331
|
Future::IO::Impl::Ppoll->_tick until $self->is_ready; |
|
235
|
50
|
|
|
|
|
703
|
return $self; |
|
236
|
|
|
|
|
|
|
} |
|
237
|
|
|
|
|
|
|
} |
|
238
|
|
|
|
|
|
|
|
|
239
|
|
|
|
|
|
|
=head1 AUTHOR |
|
240
|
|
|
|
|
|
|
|
|
241
|
|
|
|
|
|
|
Paul Evans |
|
242
|
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
=cut |
|
244
|
|
|
|
|
|
|
|
|
245
|
|
|
|
|
|
|
0x55AA; |