Acme-Sort-Sleep
view release on metacpan or search on metacpan
local/lib/perl5/IO/Async/OS.pm view on Meta::CPAN
# Should there be any other Loop classes we try before the builtin ones?
use constant LOOP_PREFER_CLASSES => ();
# Do we have Sereal available?
use constant HAVE_SEREAL => defined eval { require Sereal::Encoder; require Sereal::Decoder; };
=head1 NAME
C<IO::Async::OS> - operating system abstractions for C<IO::Async>
=head1 DESCRIPTION
This module acts as a class to provide a number of utility methods whose exact
behaviour may depend on the type of OS it is running on. It is provided as a
class so that specific kinds of operating system can override methods in it.
As well as these support functions it also provides a number of constants, all
with names beginning C<HAVE_> which describe various features that may or may
not be available on the OS or perl build. Most of these are either hard-coded
per OS, or detected at runtime.
The following constants may be overridden by environment variables.
=over 4
=item * HAVE_POSIX_FORK
True if the C<fork()> call has full POSIX semantics (full process separation).
This is true on most OSes but false on MSWin32.
This may be overridden to be false by setting the environment variable
C<IO_ASYNC_NO_FORK>.
=item * HAVE_THREADS
True if C<ithreads> are available, meaning that the C<threads> module can be
used. This depends on whether perl was built with threading support.
This may be overridable to be false by setting the environment variable
C<IO_ASYNC_NO_THREADS>.
=back
=cut
=head2 getfamilybyname
$family = IO::Async::OS->getfamilybyname( $name )
Return a protocol family value based on the given name. If C<$name> looks like
a number it will be returned as-is. The string values C<inet>, C<inet6> and
C<unix> will be converted to the appropriate C<AF_*> constant.
=cut
sub getfamilybyname
{
shift;
my ( $name ) = @_;
return undef unless defined $name;
return $name if $name =~ m/^\d+$/;
return AF_INET if $name eq "inet";
return AF_INET6() if $name eq "inet6" and defined &AF_INET6;
return AF_UNIX if $name eq "unix";
croak "Unrecognised socket family name '$name'";
}
=head2 getsocktypebyname
$socktype = IO::Async::OS->getsocktypebyname( $name )
Return a socket type value based on the given name. If C<$name> looks like a
number it will be returned as-is. The string values C<stream>, C<dgram> and
C<raw> will be converted to the appropriate C<SOCK_*> constant.
=cut
sub getsocktypebyname
{
shift;
my ( $name ) = @_;
return undef unless defined $name;
return $name if $name =~ m/^\d+$/;
return SOCK_STREAM if $name eq "stream";
return SOCK_DGRAM if $name eq "dgram";
return SOCK_RAW if $name eq "raw";
croak "Unrecognised socktype name '$name'";
}
# This one isn't documented because it's not really overridable. It's largely
# here just for completeness
sub socket
{
my $self = shift;
my ( $family, $socktype, $proto ) = @_;
croak "Cannot create a new socket without a family" unless $family;
# PF_UNSPEC and undef are both false
$family = $self->getfamilybyname( $family ) || AF_UNIX;
# SOCK_STREAM is the most likely
$socktype = $self->getsocktypebyname( $socktype ) || SOCK_STREAM;
defined $proto or $proto = 0;
if( HAVE_IO_SOCKET_IP and ( $family == AF_INET || $family == AF_INET6() ) ) {
return IO::Socket::IP->new->socket( $family, $socktype, $proto );
}
my $sock = eval {
IO::Socket->new(
Domain => $family,
Type => $socktype,
Proto => $proto,
);
};
return $sock if $sock;
# That failed. Most likely because the Domain was unrecognised. This
# usually happens if getaddrinfo returns an AF_INET6 address but we don't
# have a suitable class loaded. In this case we'll return a generic one.
# It won't be in the specific subclass but that's the best we can do. And
# it will still work as a generic socket.
return IO::Socket->new->socket( $family, $socktype, $proto );
}
=head2 socketpair
( $S1, $S2 ) = IO::Async::OS->socketpair( $family, $socktype, $proto )
An abstraction of the C<socketpair(2)> syscall, where any argument may be
missing (or given as C<undef>).
If C<$family> is not provided, a suitable value will be provided by the OS
(likely C<AF_UNIX> on POSIX-based platforms). If C<$socktype> is not provided,
then C<SOCK_STREAM> will be used.
Additionally, this method supports building connected C<SOCK_STREAM> or
C<SOCK_DGRAM> pairs in the C<AF_INET> family even if the underlying platform's
C<socketpair(2)> does not, by connecting two normal sockets together.
C<$family> and C<$socktype> may also be given symbolically as defined by
C<getfamilybyname> and C<getsocktypebyname>.
=cut
sub socketpair
{
my $self = shift;
my ( $family, $socktype, $proto ) = @_;
# PF_UNSPEC and undef are both false
$family = $self->getfamilybyname( $family ) || AF_UNIX;
# SOCK_STREAM is the most likely
$socktype = $self->getsocktypebyname( $socktype ) || SOCK_STREAM;
$proto ||= 0;
my ( $S1, $S2 ) = IO::Socket->new->socketpair( $family, $socktype, $proto );
return ( $S1, $S2 ) if defined $S1;
return unless $family == AF_INET and ( $socktype == SOCK_STREAM or $socktype == SOCK_DGRAM );
# Now lets emulate an AF_INET socketpair call
my $Stmp = IO::Async::OS->socket( $family, $socktype ) or return;
$Stmp->bind( pack_sockaddr_in( 0, INADDR_LOOPBACK ) ) or return;
$S1 = IO::Async::OS->socket( $family, $socktype ) or return;
if( $socktype == SOCK_STREAM ) {
$Stmp->listen( 1 ) or return;
$S1->connect( getsockname $Stmp ) or return;
$S2 = $Stmp->accept or return;
# There's a bug in IO::Socket here, in that $S2 's ->socktype won't
# yet be set. We can apply a horribly hacky fix here
# defined $S2->socktype and $S2->socktype == $socktype or
# ${*$S2}{io_socket_type} = $socktype;
# But for now we'll skip the test for it instead
}
else {
$S2 = $Stmp;
$S1->connect( getsockname $S2 ) or return;
$S2->connect( getsockname $S1 ) or return;
}
return ( $S1, $S2 );
}
=head2 pipepair
( $rd, $wr ) = IO::Async::OS->pipepair
An abstraction of the C<pipe(2)> syscall, which returns the two new handles.
=cut
sub pipepair
{
my $self = shift;
pipe( my ( $rd, $wr ) ) or return;
return ( $rd, $wr );
}
=head2 pipequad
( $rdA, $wrA, $rdB, $wrB ) = IO::Async::OS->pipequad
This method is intended for creating two pairs of filehandles that are linked
local/lib/perl5/IO/Async/OS.pm view on Meta::CPAN
=head2 loop_watch_signal
=head2 loop_unwatch_signal
IO::Async::OS->loop_watch_signal( $loop, $signal, $code )
IO::Async::OS->loop_unwatch_signal( $loop, $signal )
Used to implement the C<watch_signal> / C<unwatch_signal> Loop pair.
=cut
sub loop_watch_signal
{
my $self = shift;
my ( $loop, $signal, $code ) = @_;
exists $SIG{$signal} or croak "Unrecognised signal name $signal";
ref $code or croak 'Expected $code as a reference';
my $signum = $self->signame2num( $signal );
my $sigwatch = $loop->{os}{sigwatch} ||= {}; # {$num} = $code
my $sigpipe;
unless( $sigpipe = $loop->{os}{sigpipe} ) {
require IO::Async::Handle;
( my $reader, $sigpipe ) = $self->pipepair or croak "Cannot pipe() - $!";
$_->blocking( 0 ) for $reader, $sigpipe;
$loop->{os}{sigpipe} = $sigpipe;
$loop->add( $loop->{os}{sigpipe_reader} = IO::Async::Handle->new(
notifier_name => "sigpipe",
read_handle => $reader,
on_read_ready => sub {
sysread $reader, my $buffer, 8192 or return;
foreach my $signum ( unpack "I*", $buffer ) {
$sigwatch->{$signum}->() if $sigwatch->{$signum};
}
},
) );
}
my $signum_str = pack "I", $signum;
$SIG{$signal} = sub { syswrite $sigpipe, $signum_str };
$sigwatch->{$signum} = $code;
}
sub loop_unwatch_signal
{
my $self = shift;
my ( $loop, $signal ) = @_;
my $signum = $self->signame2num( $signal );
my $sigwatch = $loop->{os}{sigwatch} or return;
delete $sigwatch->{$signum};
undef $SIG{$signal};
}
=head2 potentially_open_fds
@fds = IO::Async::OS->potentially_open_fds
Returns a list of filedescriptors which might need closing. By default this
will return C<0 .. _SC_OPEN_MAX>. OS-specific subclasses may have a better
guess.
=cut
sub potentially_open_fds
{
return 0 .. OPEN_MAX_FD;
}
=head1 AUTHOR
Paul Evans <leonerd@leonerd.org.uk>
=cut
0x55AA;
( run in 1.360 second using v1.01-cache-2.11-cpan-d80b1682f3f )