File Coverage

blib/lib/IO/Async/OS.pm
Criterion Covered Total %
statement 222 231 96.1
branch 73 104 70.1
condition 43 62 69.3
subroutine 42 43 97.6
pod n/a
total 380 440 86.3


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, 2012-2024 -- leonerd@leonerd.org.uk
5              
6             package IO::Async::OS 0.805;
7              
8 103     103   1159272 use v5.14;
  103         393  
9 103     103   659 use warnings;
  103         238  
  103         14745  
10              
11             our @ISA = qw( IO::Async::OS::_Base );
12              
13             if( eval { require "IO/Async/OS/$^O.pm" } ) {
14             @ISA = "IO::Async::OS::$^O";
15             }
16              
17             package # hide from CPAN
18             IO::Async::OS::_Base;
19              
20 103     103   693 use Carp;
  103         217  
  103         9971  
21              
22 103         16786 use Socket 1.95 qw(
23             AF_INET AF_INET6 AF_UNIX INADDR_LOOPBACK SOCK_DGRAM SOCK_RAW SOCK_STREAM
24             pack_sockaddr_in inet_aton
25             pack_sockaddr_in6 inet_pton
26             pack_sockaddr_un
27 103     103   79437 );
  103         183687  
28              
29 103     103   22653 use POSIX qw( sysconf _SC_OPEN_MAX );
  103         340524  
  103         1019  
30              
31             # Win32 [and maybe other places] don't have an _SC_OPEN_MAX. About the best we
32             # can do really is just make up some largeish number and hope for the best.
33 103   50 103   87642 use constant OPEN_MAX_FD => eval { sysconf(_SC_OPEN_MAX) } || 1024;
  103         455  
  103         245  
34              
35             # Some constants that define features of the OS
36              
37 103     103   806 use constant HAVE_SOCKADDR_IN6 => defined eval { pack_sockaddr_in6 0, inet_pton( AF_INET6, "2001::1" ) };
  103         211  
  103         261  
  103         9245  
38 103     103   674 use constant HAVE_SOCKADDR_UN => defined eval { pack_sockaddr_un "/foo" };
  103         485  
  103         283  
  103         6480  
39              
40             # Do we have to fake S_ISREG() files read/write-ready in select()?
41 103     103   1178 use constant HAVE_FAKE_ISREG_READY => 0;
  103         199  
  103         5545  
42              
43             # Do we have to select() for for evec to get connect() failures
44 103     103   1061 use constant HAVE_SELECT_CONNECT_EVEC => 0;
  103         229  
  103         5456  
45             # Ditto; do we have to poll() for POLLPRI to get connect() failures
46 103     103   575 use constant HAVE_POLL_CONNECT_POLLPRI => 0;
  103         185  
  103         5916  
47              
48             # Does connect() yield EWOULDBLOCK for nonblocking in progress?
49 103     103   532 use constant HAVE_CONNECT_EWOULDBLOCK => 0;
  103         182  
  103         5440  
50              
51             # Can we rename() files that are open?
52 103     103   597 use constant HAVE_RENAME_OPEN_FILES => 1;
  103         167  
  103         4887  
53              
54             # Can we reliably watch for POSIX signals, including SIGCHLD to reliably
55             # inform us that a fork()ed child has exit()ed?
56 103     103   543 use constant HAVE_SIGNALS => 1;
  103         206  
  103         6212  
57              
58             # Do we support POSIX-style true fork()ed processes at all?
59 103     103   1256 use constant HAVE_POSIX_FORK => !$ENV{IO_ASYNC_NO_FORK};
  103         222  
  103         9367  
60             # Can we potentially support threads? (would still need to 'require threads')
61             use constant HAVE_THREADS => !$ENV{IO_ASYNC_NO_THREADS} &&
62 103   33 103   691 eval { require Config && $Config::Config{useithreads} };
  103         242  
  103         713  
63              
64             # Preferred trial order for built-in Loop classes
65 103     103   719 use constant LOOP_BUILTIN_CLASSES => qw( Poll Select );
  103         281  
  103         7901  
66              
67             # Should there be any other Loop classes we try before the builtin ones?
68 103     103   742 use constant LOOP_PREFER_CLASSES => ();
  103         293  
  103         153645  
69              
70             =head1 NAME
71              
72             C - operating system abstractions for C
73              
74             =head1 DESCRIPTION
75              
76             =for highlighter language=perl
77              
78             This module acts as a class to provide a number of utility methods whose exact
79             behaviour may depend on the type of OS it is running on. It is provided as a
80             class so that specific kinds of operating system can override methods in it.
81              
82             As well as these support functions it also provides a number of constants, all
83             with names beginning C which describe various features that may or may
84             not be available on the OS or perl build. Most of these are either hard-coded
85             per OS, or detected at runtime.
86              
87             The following constants may be overridden by environment variables.
88              
89             =over 4
90              
91             =item * HAVE_POSIX_FORK
92              
93             True if the C call has full POSIX semantics (full process separation).
94             This is true on most OSes but false on MSWin32.
95              
96             This may be overridden to be false by setting the environment variable
97             C.
98              
99             =item * HAVE_THREADS
100              
101             True if C are available, meaning that the C module can be
102             used. This depends on whether perl was built with threading support.
103              
104             This may be overridable to be false by setting the environment variable
105             C.
106              
107             =back
108              
109             =cut
110              
111             =head2 getfamilybyname
112              
113             $family = IO::Async::OS->getfamilybyname( $name )
114              
115             Return a protocol family value based on the given name. If C<$name> looks like
116             a number it will be returned as-is. The string values C, C and
117             C will be converted to the appropriate C constant.
118              
119             =cut
120              
121             sub getfamilybyname
122             {
123 156     156   296 shift;
124 156         337 my ( $name ) = @_;
125              
126 156 100       718 return undef unless defined $name;
127              
128 102 100       753 return $name if $name =~ m/^\d+$/;
129              
130 48 100       233 return AF_INET if $name eq "inet";
131 7 100 66     40 return AF_INET6() if $name eq "inet6" and defined &AF_INET6;
132 5 50       17 return AF_UNIX if $name eq "unix";
133              
134 0         0 croak "Unrecognised socket family name '$name'";
135             }
136              
137             =head2 getsocktypebyname
138              
139             $socktype = IO::Async::OS->getsocktypebyname( $name );
140              
141             Return a socket type value based on the given name. If C<$name> looks like a
142             number it will be returned as-is. The string values C, C and
143             C will be converted to the appropriate C constant.
144              
145             =cut
146              
147             sub getsocktypebyname
148             {
149 167     167   279 shift;
150 167         333 my ( $name ) = @_;
151              
152 167 100       536 return undef unless defined $name;
153              
154 114 100       529 return $name if $name =~ m/^\d+$/;
155              
156 52 100       188 return SOCK_STREAM if $name eq "stream";
157 18 50       113 return SOCK_DGRAM if $name eq "dgram";
158 0 0       0 return SOCK_RAW if $name eq "raw";
159              
160 0         0 croak "Unrecognised socktype name '$name'";
161             }
162              
163             # This one isn't documented because it's not really overridable. It's largely
164             # here just for completeness
165             my $HAVE_IO_SOCKET_IP;
166              
167             sub socket
168             {
169 44     44   310409 my $self = shift;
170 44         150 my ( $family, $socktype, $proto ) = @_;
171              
172 44         291 require IO::Socket;
173             defined $HAVE_IO_SOCKET_IP or
174 44 100       176 $HAVE_IO_SOCKET_IP = defined eval { require IO::Socket::IP };
  12         8938  
175              
176 44 50       97877 croak "Cannot create a new socket without a family" unless $family;
177             # PF_UNSPEC and undef are both false
178 44   50     209 $family = $self->getfamilybyname( $family ) || AF_UNIX;
179              
180             # SOCK_STREAM is the most likely
181 44   50     192 $socktype = $self->getsocktypebyname( $socktype ) || SOCK_STREAM;
182              
183 44   100     190 $proto //= 0;
184              
185 44 100 100     255 if( $HAVE_IO_SOCKET_IP and ( $family == AF_INET || $family == AF_INET6() ) ) {
      66        
186 42         330 return IO::Socket::IP->new->socket( $family, $socktype, $proto );
187             }
188              
189 2         3 my $sock = eval {
190 2         12 IO::Socket->new(
191             Domain => $family,
192             Type => $socktype,
193             Proto => $proto,
194             );
195             };
196 2 50       377 return $sock if $sock;
197              
198             # That failed. Most likely because the Domain was unrecognised. This
199             # usually happens if getaddrinfo returns an AF_INET6 address but we don't
200             # have a suitable class loaded. In this case we'll return a generic one.
201             # It won't be in the specific subclass but that's the best we can do. And
202             # it will still work as a generic socket.
203 0         0 return IO::Socket->new->socket( $family, $socktype, $proto );
204             }
205              
206             =head2 socketpair
207              
208             ( $S1, $S2 ) = IO::Async::OS->socketpair( $family, $socktype, $proto );
209              
210             An abstraction of the C syscall, where any argument may be
211             missing (or given as C).
212              
213             If C<$family> is not provided, a suitable value will be provided by the OS
214             (likely C on POSIX-based platforms). If C<$socktype> is not provided,
215             then C will be used.
216              
217             Additionally, this method supports building connected C or
218             C pairs in the C family even if the underlying platform's
219             C does not, by connecting two normal sockets together.
220              
221             C<$family> and C<$socktype> may also be given symbolically as defined by
222             C and C.
223              
224             =cut
225              
226             sub socketpair
227             {
228 51     51   28731 my $self = shift;
229 51         163 my ( $family, $socktype, $proto ) = @_;
230              
231 51         7844 require IO::Socket;
232              
233             # PF_UNSPEC and undef are both false
234 51   100     116200 $family = $self->getfamilybyname( $family ) || AF_UNIX;
235              
236             # SOCK_STREAM is the most likely
237 51   100     283 $socktype = $self->getsocktypebyname( $socktype ) || SOCK_STREAM;
238              
239 51   50     318 $proto ||= 0;
240              
241 51         363 my ( $S1, $S2 ) = IO::Socket->new->socketpair( $family, $socktype, $proto );
242 51 100       15552 return ( $S1, $S2 ) if defined $S1;
243              
244 11 50 66     158 return unless $family == AF_INET and ( $socktype == SOCK_STREAM or $socktype == SOCK_DGRAM );
      33        
245              
246             # Now lets emulate an AF_INET socketpair call
247              
248 11 50       139 my $Stmp = IO::Async::OS->socket( $family, $socktype ) or return;
249 11 50       1969 $Stmp->bind( pack_sockaddr_in( 0, INADDR_LOOPBACK ) ) or return;
250              
251 11 50       422 $S1 = IO::Async::OS->socket( $family, $socktype ) or return;
252              
253 11 100       1325 if( $socktype == SOCK_STREAM ) {
254 2 50       23 $Stmp->listen( 1 ) or return;
255 2 50       68 $S1->connect( getsockname $Stmp ) or return;
256 2 50       359 $S2 = $Stmp->accept or return;
257              
258             # There's a bug in IO::Socket here, in that $S2 's ->socktype won't
259             # yet be set. We can apply a horribly hacky fix here
260             # defined $S2->socktype and $S2->socktype == $socktype or
261             # ${*$S2}{io_socket_type} = $socktype;
262             # But for now we'll skip the test for it instead
263             }
264             else {
265 9         17 $S2 = $Stmp;
266 9 50       154 $S1->connect( getsockname $S2 ) or return;
267 9 50       341 $S2->connect( getsockname $S1 ) or return;
268             }
269              
270 11         656 return ( $S1, $S2 );
271             }
272              
273             =head2 pipepair
274              
275             ( $rd, $wr ) = IO::Async::OS->pipepair;
276              
277             An abstraction of the C syscall, which returns the two new handles.
278              
279             =cut
280              
281             sub pipepair
282             {
283 801     801   28869 my $self = shift;
284              
285 801 50       39110 pipe( my ( $rd, $wr ) ) or return;
286 801         6273 return ( $rd, $wr );
287             }
288              
289             =head2 pipequad
290              
291             ( $rdA, $wrA, $rdB, $wrB ) = IO::Async::OS->pipequad;
292              
293             This method is intended for creating two pairs of filehandles that are linked
294             together, suitable for passing as the STDIN/STDOUT pair to a child process.
295             After this function returns, C<$rdA> and C<$wrA> will be a linked pair, as
296             will C<$rdB> and C<$wrB>.
297              
298             On platforms that support C, this implementation will be
299             preferred, in which case C<$rdA> and C<$wrB> will actually be the same
300             filehandle, as will C<$rdB> and C<$wrA>. This saves a file descriptor in the
301             parent process.
302              
303             When creating a L or subclass of it, the C
304             and C parameters should always be used.
305              
306             my ( $childRd, $myWr, $myRd, $childWr ) = IO::Async::OS->pipequad;
307              
308             $loop->open_process(
309             stdin => $childRd,
310             stdout => $childWr,
311             ...
312             );
313              
314             my $str = IO::Async::Stream->new(
315             read_handle => $myRd,
316             write_handle => $myWr,
317             ...
318             );
319             $loop->add( $str );
320              
321             =cut
322              
323             sub pipequad
324             {
325 2     2   3739 my $self = shift;
326              
327             # Prefer socketpair
328 2 50       27 if( my ( $S1, $S2 ) = $self->socketpair ) {
329 2         12 return ( $S1, $S2, $S2, $S1 );
330             }
331              
332             # Can't do that, fallback on pipes
333 0 0       0 my ( $rdA, $wrA ) = $self->pipepair or return;
334 0 0       0 my ( $rdB, $wrB ) = $self->pipepair or return;
335              
336 0         0 return ( $rdA, $wrA, $rdB, $wrB );
337             }
338              
339             =head2 signame2num
340              
341             $signum = IO::Async::OS->signame2num( $signame );
342              
343             This utility method converts a signal name (such as "TERM") into its system-
344             specific signal number. This may be useful to pass to C or use
345             in other places which use numbers instead of symbolic names.
346              
347             =head2 signum2name
348              
349             $signame = IO::Async::OS->signum2name( $signum );
350              
351             The inverse of L; this method convers signal numbers into
352             readable names.
353              
354             =cut
355              
356             my %sig_name2num;
357             my %sig_num2name;
358              
359             sub _init_signum
360             {
361 58     58   249 my $self = shift;
362              
363 58         1499 require Config;
364              
365             $Config::Config{sig_name} and $Config::Config{sig_num} or
366 58 50 33     34203 die "No signals found";
367              
368 58         6792 my @names = split ' ', $Config::Config{sig_name};
369 58         2234 my @nums = split ' ', $Config::Config{sig_num};
370              
371 58         6020 @sig_name2num{ @names } = @nums;
372              
373             # Only take the first of each name, in case of aliased names
374 58   66     85736 @sig_num2name{ $sig_name2num{$_} } //= $_ for @names;
375             }
376              
377             sub signame2num
378             {
379 212     212   1289 my $self = shift;
380 212         461 my ( $signame ) = @_;
381              
382 212 100       2505 %sig_name2num or $self->_init_signum;
383              
384 212         820 return $sig_name2num{$signame};
385             }
386              
387             sub signum2name
388             {
389 2     2   4 my $self = shift;
390 2         3 my ( $signum ) = @_;
391              
392 2 50       8 %sig_num2name or $self->_init_signum;
393              
394 2         8 return $sig_num2name{$signum};
395             }
396              
397             =head2 extract_addrinfo
398              
399             ( $family, $socktype, $protocol, $addr ) = IO::Async::OS->extract_addrinfo( $ai );
400              
401             Given an ARRAY or HASH reference value containing an addrinfo, returns a
402             family, socktype and protocol argument suitable for a C call and an
403             address suitable for C or C.
404              
405             If given an ARRAY it should be in the following form:
406              
407             [ $family, $socktype, $protocol, $addr ]
408              
409             If given a HASH it should contain the following keys:
410              
411             family socktype protocol addr
412              
413             Each field in the result will be initialised to 0 (or empty string for the
414             address) if not defined in the C<$ai> value.
415              
416             The family type may also be given as a symbolic string as defined by
417             C.
418              
419             The socktype may also be given as a symbolic string; C, C or
420             C; this will be converted to the appropriate C constant.
421              
422             Note that the C field, if provided, must be a packed socket address,
423             such as returned by C or C.
424              
425             If the HASH form is used, rather than passing a packed socket address in the
426             C field, certain other hash keys may be used instead for convenience on
427             certain named families.
428              
429             =over 4
430              
431             =cut
432              
433 103     103   974 use constant ADDRINFO_FAMILY => 0;
  103         169  
  103         7904  
434 103     103   607 use constant ADDRINFO_SOCKTYPE => 1;
  103         179  
  103         7070  
435 103     103   594 use constant ADDRINFO_PROTOCOL => 2;
  103         340  
  103         5634  
436 103     103   582 use constant ADDRINFO_ADDR => 3;
  103         224  
  103         174031  
437              
438             sub extract_addrinfo
439             {
440 55     55   1557 my $self = shift;
441 55         131 my ( $ai, $argname ) = @_;
442              
443 55   100     242 $argname ||= "addr";
444              
445 55         85 my @ai;
446              
447 55 100       179 if( ref $ai eq "ARRAY" ) {
    50          
448 4         13 @ai = @$ai;
449             }
450             elsif( ref $ai eq "HASH" ) {
451 51         191 $ai = { %$ai }; # copy so we can delete from it
452 51         104 @ai = delete @{$ai}{qw( family socktype protocol addr )};
  51         146  
453              
454 51 100 100     207 if( defined $ai[ADDRINFO_FAMILY] and !defined $ai[ADDRINFO_ADDR] ) {
455 15         25 my $family = $ai[ADDRINFO_FAMILY];
456 15         30 my $method = "_extract_addrinfo_$family";
457 15 100       331 my $code = $self->can( $method ) or croak "Cannot determine addr for extract_addrinfo on family='$family'";
458              
459 14         54 $ai[ADDRINFO_ADDR] = $code->( $self, $ai );
460              
461 14 100       294 keys %$ai and croak "Unrecognised '$family' addrinfo keys: " . join( ", ", keys %$ai );
462             }
463             }
464             else {
465 0         0 croak "Expected '$argname' to be an ARRAY or HASH reference";
466             }
467              
468 53         184 $ai[ADDRINFO_FAMILY] = $self->getfamilybyname( $ai[ADDRINFO_FAMILY] );
469 53         177 $ai[ADDRINFO_SOCKTYPE] = $self->getsocktypebyname( $ai[ADDRINFO_SOCKTYPE] );
470              
471             # Make sure all fields are defined
472 53   100     324 $ai[$_] ||= 0 for ADDRINFO_FAMILY, ADDRINFO_SOCKTYPE, ADDRINFO_PROTOCOL;
473 53 100       135 $ai[ADDRINFO_ADDR] = "" if !defined $ai[ADDRINFO_ADDR];
474              
475 53         295 return @ai;
476             }
477              
478             =item family => 'inet'
479              
480             Will pack an IP address and port number from keys called C and C.
481             If C is missing it will be set to "0.0.0.0". If C is missing it will
482             be set to 0.
483              
484             =cut
485              
486             sub _extract_addrinfo_inet
487             {
488 8     8   12 my $self = shift;
489 8         38 my ( $ai ) = @_;
490              
491 8   100     30 my $port = delete $ai->{port} || 0;
492 8   100     25 my $ip = delete $ai->{ip} || "0.0.0.0";
493              
494 8         121 return pack_sockaddr_in( $port, inet_aton( $ip ) );
495             }
496              
497             =item family => 'inet6'
498              
499             Will pack an IP address and port number from keys called C and C.
500             If C is missing it will be set to "::". If C is missing it will be
501             set to 0. Optionally will also include values from C and C
502             keys if provided.
503              
504             This will only work if a C function can be found in
505             C
506              
507             =cut
508              
509             sub _extract_addrinfo_inet6
510             {
511 1     1   2 my $self = shift;
512 1         4 my ( $ai ) = @_;
513              
514 1   50     4 my $port = delete $ai->{port} || 0;
515 1   50     5 my $ip = delete $ai->{ip} || "::";
516 1   50     6 my $scopeid = delete $ai->{scopeid} || 0;
517 1   50     6 my $flowinfo = delete $ai->{flowinfo} || 0;
518              
519 1         6 if( HAVE_SOCKADDR_IN6 ) {
520 1         37 return pack_sockaddr_in6( $port, inet_pton( AF_INET6, $ip ), $scopeid, $flowinfo );
521             }
522             else {
523             croak "Cannot pack_sockaddr_in6";
524             }
525             }
526              
527             =item family => 'unix'
528              
529             Will pack a UNIX socket path from a key called C.
530              
531             =cut
532              
533             sub _extract_addrinfo_unix
534             {
535 5     5   11 my $self = shift;
536 5         10 my ( $ai ) = @_;
537              
538 5 50       16 defined( my $path = delete $ai->{path} ) or croak "Expected 'path' for extract_addrinfo on family='unix'";
539              
540 5         41 return pack_sockaddr_un( $path );
541             }
542              
543             =pod
544              
545             =back
546              
547             =cut
548              
549             =head2 make_addr_for_peer
550              
551             $connectaddr = IO::Async::OS->make_addr_for_peer( $family, $listenaddr );
552              
553             Given the C and C of a listening socket. creates an
554             address suitable to C to it.
555              
556             This method will handle specially any C address bound to
557             C or any C address bound to C, as some OSes
558             do not allow Cing to those and would instead insist on receiving
559             C or C respectively.
560              
561             This method is used by the C<< ->connect( peer => $sock ) >> parameter of
562             handle and loop connect methods.
563              
564             =cut
565              
566             sub make_addr_for_peer
567             {
568 5     5   2276 shift;
569 5         14 my ( $p_family, $p_addr ) = @_;
570              
571 5 100       32 if( $p_family == Socket::AF_INET ) {
572 2         8 my @params = Socket::unpack_sockaddr_in $p_addr;
573 2 100       7 $params[1] = Socket::INADDR_LOOPBACK if $params[1] eq Socket::INADDR_ANY;
574 2         10 return Socket::pack_sockaddr_in @params;
575             }
576 3 100       11 if( HAVE_SOCKADDR_IN6 and $p_family == Socket::AF_INET6 ) {
577 2         9 my @params = Socket::unpack_sockaddr_in6 $p_addr;
578 2 100       27 $params[1] = Socket::IN6ADDR_LOOPBACK if $params[1] eq Socket::IN6ADDR_ANY;
579 2         18 return Socket::pack_sockaddr_in6 @params;
580             }
581              
582             # Most other cases should be fine
583 1         8 return $p_addr;
584             }
585              
586             =head1 LOOP IMPLEMENTATION METHODS
587              
588             The following methods are provided on C because they are likely
589             to require OS-specific implementations, but are used by L to
590             implement its functionality. It can use the HASH reference C<< $loop->{os} >>
591             to store other data it requires.
592              
593             =cut
594              
595             =head2 loop_watch_signal
596              
597             =head2 loop_unwatch_signal
598              
599             IO::Async::OS->loop_watch_signal( $loop, $signal, $code );
600              
601             IO::Async::OS->loop_unwatch_signal( $loop, $signal );
602              
603             Used to implement the C / C Loop pair.
604              
605             =cut
606              
607             sub _setup_sigpipe
608             {
609 59     59   223 my $self = shift;
610 59         156 my ( $loop ) = @_;
611              
612 59         27550 require IO::Async::Handle;
613              
614 59 50       1076 my ( $reader, $sigpipe ) = $self->pipepair or croak "Cannot pipe() - $!";
615 59         1549 $_->blocking( 0 ) for $reader, $sigpipe;
616              
617 59         454 $loop->{os}{sigpipe} = $sigpipe;
618              
619 59         157 my $sigwatch = $loop->{os}{sigwatch};
620              
621             $loop->add( $loop->{os}{sigpipe_reader} = IO::Async::Handle->new(
622             notifier_name => "sigpipe",
623             read_handle => $reader,
624             on_read_ready => sub {
625 326 50   326   5691 sysread $reader, my $buffer, 8192 or return;
626 326         2044 foreach my $signum ( unpack "I*", $buffer ) {
627 330 50       2765 $sigwatch->{$signum}->() if $sigwatch->{$signum};
628             }
629             },
630 59         1715 ) );
631              
632 59         287 return $sigpipe;
633             }
634              
635             sub loop_watch_signal
636             {
637 70     70   410 my $self = shift;
638 70         269 my ( $loop, $signal, $code ) = @_;
639              
640 70 100       1478 exists $SIG{$signal} or croak "Unrecognised signal name $signal";
641 67 50       364 ref $code or croak 'Expected $code as a reference';
642              
643 67         2610 my $signum = $self->signame2num( $signal );
644 67   100     2132 my $sigwatch = $loop->{os}{sigwatch} ||= {}; # {$num} = $code
645              
646 67   66     1631 my $sigpipe = $loop->{os}{sigpipe} // $self->_setup_sigpipe( $loop );
647              
648 67         527 my $signum_str = pack "I", $signum;
649 67     331   2006 $SIG{$signal} = sub { syswrite $sigpipe, $signum_str };
  331         61541  
650              
651 67         687 $sigwatch->{$signum} = $code;
652             }
653              
654             sub loop_unwatch_signal
655             {
656 9     9   25 my $self = shift;
657 9         159 my ( $loop, $signal ) = @_;
658              
659 9         54 my $signum = $self->signame2num( $signal );
660 9 50       64 my $sigwatch = $loop->{os}{sigwatch} or return;
661              
662 9         68 delete $sigwatch->{$signum};
663 9         247 undef $SIG{$signal};
664             }
665              
666             =head2 potentially_open_fds
667              
668             @fds = IO::Async::OS->potentially_open_fds;
669              
670             Returns a list of filedescriptors which might need closing. By default this
671             will return C<0 .. _SC_OPEN_MAX>. OS-specific subclasses may have a better
672             guess.
673              
674             =cut
675              
676             sub potentially_open_fds
677             {
678 0     0   0 return 0 .. OPEN_MAX_FD;
679             }
680              
681             sub post_fork
682             {
683 6     6   19 my $self = shift;
684 6         22 my ( $loop ) = @_;
685              
686 6 100       42 if( $loop->{os}{sigpipe} ) {
687 2         20 $loop->remove( $loop->{os}{sigpipe_reader} );
688 2         5 undef $loop->{os}{sigpipe};
689              
690 2         5 my $sigwatch = $loop->{os}{sigwatch};
691              
692 2         53 foreach my $signal ( keys %SIG ) {
693 134 50       301 my $signum = $self->signame2num( $signal ) or next;
694 134 100       346 my $code = $sigwatch->{$signum} or next;
695              
696 2         8 $self->loop_watch_signal( $loop, $signal, $code );
697             }
698             }
699             }
700              
701             =head1 AUTHOR
702              
703             Paul Evans
704              
705             =cut
706              
707             0x55AA;