NAME
IO::SigGuard - SA_RESTART in pure Perl
SYNOPSIS
IO::SigGuard::sysread( $fh, $buf, $size );
IO::SigGuard::sysread( $fh, $buf, $size, $offset );
IO::SigGuard::syswrite( $fh, $buf );
IO::SigGuard::syswrite( $fh, $buf, $len );
IO::SigGuard::syswrite( $fh, $buf, $len, $offset );
IO::SigGuard::send( $fh, $msg, $flags );
IO::SigGuard::send( $fh, $msg, $flags, $to );
IO::SigGuard::select( $read, $write, $exc, $timeout );
DESCRIPTION
perldoc perlipc describes how Perl versions from 5.8.0 onward disable
the OS’s SA_RESTART flag when installing Perl signal handlers.
This module imitates that pattern in pure Perl: it does an automatic
restart when a signal interrupts an operation so you can avoid
the generally-useless EINTR error when using
sysread(), syswrite(), and select().
For this to work, whatever signal handler you implement will need to break
out of this module, probably via either die() or exit().
ABOUT sysread() and syswrite()
Other than that you’ll never see EINTR and that
there are no function prototypes used (i.e., you need parentheses on
all invocations), sysread() and syswrite()
work exactly the same as Perl’s equivalent built-ins.
LAZY-LOADING
As of version 0.13 this module’s functions lazy-load by default. To have functionality loaded at compile time give the function name to the import logic, e.g.:
use IO::SigGuard qw(send recv);
ABOUT select()
To handle EINTR, IO::SigGuard::select() has to subtract the elapsed time
from the given timeout then repeat the internal select(). Because
the select() built-in’s $timeleft return is not reliable across
all platforms, we have to compute the elapsed time ourselves. By default the
only means of doing this is the time() built-in, which can only measure
individual seconds.
This works, but there are two ways to make it more accurate:
- Have Time::HiRes loaded, and
IO::SigGuard::select()will use that module rather than thetime()built-in. - Set
$IO::SigGuard::TIME_CRto a compatible code reference. This is useful, e.g., if you have your own logic to do the equivalent of Time::HiRes—for example, in Linux you may prefer to call thegettimeofdaysystem call directly from Perl to avoid Time::HiRes’s XS overhead.
In scalar contact, IO::SigGuard::select() is a drop-in replacement
for Perl’s 4-argument built-in.
In list context, there may be discrepancies re the $timeleft value
that Perl returns from a call to select. As per Perl’s documentation
this value is generally not reliable anyway, though, so that shouldn’t be a
big deal. In fact, on systems like MacOS where the built-in’s $timeleft
is completely useless, IO::SigGuard’s return is actually better since it
does provide at least a rough estimate of how much of the given timeout value
is left.
See perlport for portability notes for select.
TODO
This pattern could probably be extended to other system calls that can receive EINTR. I’ll consider adding new calls as requested.
REPOSITORY
https://github.com/FGasper/p5-IO-SigGuard
AUTHOR
Felipe Gasper (FELIPE)
… with special thanks to Mario Roy (MARIOROY) for extra testing and a few fixes/improvements.
COPYRIGHT
Copyright 2017 by Gasper Software Consulting
LICENSE
This distribution is released under the same license as Perl.