|
perlipc - Perl interprocess communication (signals, fifos, pipes, safe subprocesses, sockets, and semaphores)
The basic IPC facilities of Perl are built out of the good old Unix
signals, named pipes, pipe opens, the Berkeley socket routines, and SysV
IPC calls. Each is used in slightly different situations.
Perl uses a simple signal handling model: the %SIG hash contains names
or references of user-installed signal handlers. These handlers will
be called with an argument which is the name of the signal that
triggered it. A signal may be generated intentionally from a
particular keyboard sequence like control-C or control-Z, sent to you
from another process, or triggered automatically by the kernel when
special events transpire, like a child process exiting, your process
running out of stack space, or hitting file size limit.
For example, to trap an interrupt signal, set up a handler like this:
sub catch_zap {
my $signame = shift;
$shucks++;
die "Somebody sent me a SIG$signame";
}
$SIG{INT} = 'catch_zap';
$SIG{INT} = \&catch_zap;
Prior to Perl 5.7.3 it was necessary to do as little as you possibly
could in your handler; notice how all we do is set a global variable
and then raise an exception. That's because on most systems,
libraries are not re-entrant; particularly, memory allocation and I/O
routines are not. That meant that doing nearly anything in your
handler could in theory trigger a memory fault and subsequent core
dump - see Deferred Signals (Safe Signals) below.
The names of the signals are the ones listed out by kill -l on your
system, or you can retrieve them from the Config module. Set up an
@signame list indexed by number to get the name and a %signo table
indexed by name to get the number:
use Config;
defined $Config{sig_name} || die "No sigs?";
foreach $name (split(' ', $Config{sig_name})) {
$signo{$name} = $i;
$signame[$i] = $name;
$i++;
}
So to check whether signal 17 and SIGALRM were the same, do just this:
print "signal #17 = $signame[17]\n";
if ($signo{ALRM}) {
print "SIGALRM is $signo{ALRM}\n";
}
You may also choose to assign the strings 'IGNORE' or 'DEFAULT' as
the handler, in which case Perl will try to discard the signal or do the
default thing.
On most Unix platforms, the CHLD (sometimes also known as CLD) signal
has special behavior with respect to a value of 'IGNORE'.
Setting $SIG{CHLD} to 'IGNORE' on such a platform has the effect of
not creating zombie processes when the parent process fails to wait()
on its child processes (i.e. child processes are automatically reaped).
Calling wait() with $SIG{CHLD} set to 'IGNORE' usually returns
-1 on such platforms.
Some signals can be neither trapped nor ignored, such as
the KILL and STOP (but not the TSTP) signals. One strategy for
temporarily ignoring signals is to use a local() statement, which will be
automatically restored once your block is exited. (Remember that local()
values are "inherited" by functions called from within that block.)
sub precious {
local $SIG{INT} = 'IGNORE';
&more_functions;
}
sub more_functions {
}
Sending a signal to a negative process ID means that you send the signal
to the entire Unix process-group. This code sends a hang-up signal to all
processes in the current process group (and sets $SIG{HUP} to IGNORE so
it doesn't kill itself):
{
local $SIG{HUP} = 'IGNORE';
kill HUP => -$$;
}
Another interesting signal to send is signal number zero. This doesn't
actually affect a child process, but instead checks whether it's alive
or has changed its UID.
unless (kill 0 => $kid_pid) {
warn "something wicked happened to $kid_pid";
}
When directed at a process whose UID is not identical to that
of the sending process, signal number zero may fail because
you lack permission to send the signal, even though the process is alive.
You may be able to determine the cause of failure using %!.
unless (kill 0 => $pid or $!{EPERM}) {
warn "$pid looks dead";
}
You might also want to employ anonymous functions for simple signal
handlers:
$SIG{INT} = sub { die "\nOutta here!\n" };
But that will be problematic for the more complicated handlers that need
to reinstall themselves. Because Perl's signal mechanism is currently
based on the signal(3) function from the C library, you may sometimes be so
misfortunate as to run on systems where that function is "broken", that
is, it behaves in the old unreliable SysV way rather than the newer, more
reasonable BSD and POSIX fashion. So you'll see defensive people writing
signal handlers like this:
sub REAPER {
$waitedpid = wait;
$SIG{CHLD} = \&REAPER;
}
$SIG{CHLD} = \&REAPER;
or better still:
use POSIX ":sys_wait_h";
sub REAPER {
my $child;
while (($child = waitpid(-1,WNOHANG)) > 0) {
$Kid_Status{$child} = $?;
}
$SIG{CHLD} = \&REAPER;
}
$SIG{CHLD} = \&REAPER;
Signal handling is also used for timeouts in Unix, While safely
protected within an eval{} block, you set a signal handler to trap
alarm signals and then schedule to have one delivered to you in some
number of seconds. Then try your blocking operation, clearing the alarm
when it's done but not before you've exited your eval{} block. If it
goes off, you'll use die() to jump out of the block, much as you might
using longjmp() or throw() in other languages.
Here's an example:
eval {
local $SIG{ALRM} = sub { die "alarm clock restart" };
alarm 10;
flock(FH, 2);
alarm 0;
};
if ($@ and $@ !~ /alarm clock restart/) { die }
If the operation being timed out is system() or qx(), this technique
is liable to generate zombies. If this matters to you, you'll
need to do your own fork() and exec(), and kill the errant child process.
For more complex signal handling, you might see the standard POSIX
module. Lamentably, this is almost entirely undocumented, but
the t/lib/posix.t file from the Perl source distribution has some
examples in it.
A process that usually starts when the system boots and shuts down
when the system is shut down is called a daemon (Disk And Execution
MONitor). If a daemon process has a configuration file which is
modified after the process has been started, there should be a way to
tell that process to re-read its configuration file, without stopping
the process. Many daemons provide this mechanism using the SIGHUP
signal handler. When you want to tell the daemon to re-read the file
you simply send it the SIGHUP signal.
Not all platforms automatically reinstall their (native) signal
handlers after a signal delivery. This means that the handler works
only the first time the signal is sent. The solution to this problem
is to use POSIX signal handlers if available, their behaviour
is well-defined.
The following example implements a simple daemon, which restarts
itself every time the SIGHUP signal is received. The actual code is
located in the subroutine code(), which simply prints some debug
info to show that it works and should be replaced with the real code.
use POSIX ();
use FindBin ();
use File::Basename ();
use File::Spec::Functions;
$|=1;
my $script = File::Basename::basename($0);
my $SELF = catfile $FindBin::Bin, $script;
my $sigset = POSIX::SigSet->new();
my $action = POSIX::SigAction->new('sigHUP_handler',
$sigset,
&POSIX::SA_NODEFER);
POSIX::sigaction(&POSIX::SIGHUP, $action);
sub sigHUP_handler {
print "got SIGHUP\n";
exec($SELF, @ARGV) or die "Couldn't restart: $!\n";
}
code();
sub code {
print "PID: $$\n";
print "ARGV: @ARGV\n";
my $c = 0;
while (++$c) {
sleep 2;
print "$c\n";
}
}
A named pipe (often referred to as a FIFO) is an old Unix IPC
mechanism for processes communicating on the same machine. It works
just like a regular, connected anonymous pipes, except that the
processes rendezvous using a filename and don't have to be related.
To create a named pipe, use the POSIX::mkfifo() function.
use POSIX qw(mkfifo);
mkfifo($path, 0700) or die "mkfifo $path failed: $!";
You can also use the Unix command mknod(1) or on some
systems, mkfifo(1). These may not be in your normal path.
$ENV{PATH} .= ":/etc:/usr/etc";
if ( system('mknod', $path, 'p')
&& system('mkfifo', $path) )
{
die "mk{nod,fifo} $path failed";
}
A fifo is convenient when you want to connect a process to an unrelated
one. When you open a fifo, the program will block until there's something
on the other end.
For example, let's say you'd like to have your .signature file be a
named pipe that has a Perl program on the other end. Now every time any
program (like a mailer, news reader, finger program, etc.) tries to read
from that file, the reading program will block and your program will
supply the new signature. We'll use the pipe-checking file test -p
to find out whether anyone (or anything) has accidentally removed our fifo.
chdir;
$FIFO = '.signature';
while (1) {
unless (-p $FIFO) {
unlink $FIFO;
require POSIX;
POSIX::mkfifo($FIFO, 0700)
or die "can't mkfifo $FIFO: $!";
}
open (FIFO, "> $FIFO") || die "can't write $FIFO: $!";
print FIFO "John Smith (smith\@host.org)\n", `fortune -s`;
close FIFO;
sleep 2;
}
In Perls before Perl 5.7.3 by installing Perl code to deal with
signals, you were exposing yourself to danger from two things. First,
few system library functions are re-entrant. If the signal interrupts
while Perl is executing one function (like malloc(3) or printf(3)),
and your signal handler then calls the same function again, you could
get unpredictable behavior--often, a core dump. Second, Perl isn't
itself re-entrant at the lowest levels. If the signal interrupts Perl
while Perl is changing its own internal data structures, similarly
unpredictable behaviour may result.
There were two things you could do, knowing this: be paranoid or be
pragmatic. The paranoid approach was to do as little as possible in your
signal handler. Set an existing integer variable that already has a
value, and return. This doesn't help you if you're in a slow system call,
which will just restart. That means you have to die to longjmp(3) out
of the handler. Even this is a little cavalier for the true paranoiac,
who avoids die in a handler because the system is out to get you.
The pragmatic approach was to say "I know the risks, but prefer the
convenience", and to do anything you wanted in your signal handler,
and be prepared to clean up core dumps now and again.
In Perl 5.7.3 and later to avoid these problems signals are
"deferred"-- that is when the signal is delivered to the process by
the system (to the C code that implements Perl) a flag is set, and the
handler returns immediately. Then at strategic "safe" points in the
Perl interpreter (e.g. when it is about to execute a new opcode) the
flags are checked and the Perl level handler from %SIG is
executed. The "deferred" scheme allows much more flexibility in the
coding of signal handler as we know Perl interpreter is in a safe
state, and that we are not in a system library function when the
handler is called. However the implementation does differ from
previous Perls in the following ways:
- Long-running opcodes
-
As the Perl interpreter only looks at the signal flags when it is about
to execute a new opcode, a signal that arrives during a long-running
opcode (e.g. a regular expression operation on a very large string) will
not be seen until the current opcode completes.
-
N.B. If a signal of any given type fires multiple times during an opcode
(such as from a fine-grained timer), the handler for that signal will
only be called once after the opcode completes, and all the other
instances will be discarded. Furthermore, if your system's signal queue
gets flooded to the point that there are signals that have been raised
but not yet caught (and thus not deferred) at the time an opcode
completes, those signals may well be caught and deferred during
subsequent opcodes, with sometimes surprising results. For example, you
may see alarms delivered even after calling alarm(0) as the latter
stops the raising of alarms but does not cancel the delivery of alarms
raised but not yet caught. Do not depend on the behaviors described in
this paragraph as they are side effects of the current implementation and
may change in future versions of Perl.
- Interrupting IO
-
When a signal is delivered (e.g. INT control-C) the operating system
breaks into IO operations like read (used to implement Perls
<> operator). On older Perls the handler was called
immediately (and as read is not "unsafe" this worked well). With
the "deferred" scheme the handler is not called immediately, and if
Perl is using system's stdio library that library may re-start the
read without returning to Perl and giving it a chance to call the
%SIG handler. If this happens on your system the solution is to use
:perlio layer to do IO - at least on those handles which you want
to be able to break into with signals. (The :perlio layer checks
the signal flags and calls %SIG handlers before resuming IO operation.)
-
Note that the default in Perl 5.7.3 and later is to automatically use
the :perlio layer.
-
Note that some networking library functions like gethostbyname() are
known to have their own implementations of timeouts which may conflict
with your timeouts. If you are having problems with such functions,
you can try using the POSIX sigaction() function, which bypasses the
Perl safe signals (note that this means subjecting yourself to
possible memory corruption, as described above). Instead of setting
$SIG{ALRM}:
-
local $SIG{ALRM} = sub { die "alarm" };
-
try something like the following:
-
use POSIX qw(SIGALRM);
POSIX::sigaction(SIGALRM,
POSIX::SigAction->new(sub { die "alarm" }))
or die "Error setting SIGALRM handler: $!\n";
-
Another way to disable the safe signal behavior locally is to use
the Perl::Unsafe::Signals module from CPAN (which will affect
all signals).
- Restartable system calls
-
On systems that supported it, older versions of Perl used the
SA_RESTART flag when installing %SIG handlers. This meant that
restartable system calls would continue rather than returning when
a signal arrived. In order to deliver deferred signals promptly,
Perl 5.7.3 and later do not use SA_RESTART. Consequently,
restartable system calls can fail (with $! set to EINTR) in places
where they previously would have succeeded.
-
Note that the default :perlio layer will retry read, write
and close as described above and that interrupted wait and
waitpid calls will always be retried.
- Signals as "faults"
-
Certain signals, e.g. SEGV, ILL, and BUS, are generated as a result of
virtual memory or other "faults". These are normally fatal and there is
little a Perl-level handler can do with them, so Perl now delivers them
immediately rather than attempting to defer them.
- Signals triggered by operating system state
-
On some operating systems certain signal handlers are supposed to "do
something" before returning. One example can be CHLD or CLD which
indicates a child process has completed. On some operating systems the
signal handler is expected to wait for the completed child
process. On such systems the deferred signal scheme will not work for
those signals (it does not do the wait). Again the failure will
look like a loop as the operating system will re-issue the signal as
there are un-waited-for completed child processes.
If you want the old signal behaviour back regardless of possible
memory corruption, set the environment variable PERL_SIGNALS to
"unsafe" (a new feature since Perl 5.8.1).
Perl's basic open() statement can also be used for unidirectional
interprocess communication by either appending or prepending a pipe
symbol to the second argument to open(). Here's how to start
something up in a child process you intend to write to:
open(SPOOLER, "| cat -v | lpr -h 2>/dev/null")
|| die "can't fork: $!";
local $SIG{PIPE} = sub { die "spooler pipe broke" };
print SPOOLER "stuff\n";
close SPOOLER || die "bad spool: $! $?";
And here's how to start up a child process you intend to read from:
open(STATUS, "netstat -an 2>&1 |")
|| die "can't fork: $!";
while (<STATUS>) {
next if /^(tcp|udp)/;
print;
}
close STATUS || die "bad netstat: $! $?";
If one can be sure that a particular program is a Perl script that is
expecting filenames in @ARGV, the clever programmer can write something
like this:
% program f1 "cmd1|" - f2 "cmd2|" f3 < tmpfile
and irrespective of which shell it's called from, the Perl program will
read from the file f1, the process cmd1, standard input (tmpfile
in this case), the f2 file, the cmd2 com |