Document the UTF-8 env issue. Now NI-S just needs
[p5sagit/p5-mst-13.2.git] / pod / perlipc.pod
index e687304..2df556f 100644 (file)
@@ -10,21 +10,16 @@ IPC calls.  Each is used in slightly different situations.
 
 =head1 Signals
 
-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.
-Do as little as you possibly can 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 means that doing nearly I<anything> in your
-handler could in theory trigger a memory fault and subsequent core dump.
+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;
@@ -34,6 +29,14 @@ handler could in theory trigger a memory fault and subsequent core dump.
     $SIG{INT} = 'catch_zap';  # could fail in modules
     $SIG{INT} = \&catch_zap;  # best strategy
 
+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 I<anything> in your
+handler could in theory trigger a memory fault and subsequent core
+dump - see L<Deferred Signals> below.
+
 The names of the signals are the ones listed out by C<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
@@ -121,12 +124,16 @@ signal handlers like this:
     $SIG{CHLD} = \&REAPER;
     # now do something that forks...
 
-or even the more elaborate:
+or better still:
 
     use POSIX ":sys_wait_h";
     sub REAPER {
        my $child;
-        while ($child = waitpid(-1,WNOHANG)) {
+       # If a second child dies while in the signal handler caused by the
+       # first death, we won't get another signal. So must loop here else
+       # we will leave the unreaped child as a zombie. And the next time
+       # two children die we get another zombie. And so on.
+        while (($child = waitpid(-1,WNOHANG)) > 0) {
            $Kid_Status{$child} = $?;
        }
        $SIG{CHLD} = \&REAPER;  # still loathe sysV
@@ -152,11 +159,77 @@ Here's an example:
     };
     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 F<t/lib/posix.t> file from the Perl source distribution has some
 examples in it.
 
+=head2 Handling the SIGHUP Signal in Daemons
+
+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 C<SIGHUP>
+signal handler. When you want to tell the daemon to re-read the file
+you simply send it the C<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 C<POSIX> signal handlers if available, their behaviour
+is well-defined.
+
+The following example implements a simple daemon, which restarts
+itself every time the C<SIGHUP> signal is received. The actual code is
+located in the subroutine C<code()>, which simply prints some debug
+info to show that it works and should be replaced with the real code.
+
+  #!/usr/bin/perl -w
+  
+  use POSIX ();
+  use FindBin ();
+  use File::Basename ();
+  use File::Spec::Functions;
+  
+  $|=1;
+  
+  # make the daemon cross-platform, so exec always calls the script
+  # itself with the right path, no matter how the script was invoked.
+  my $script = File::Basename::basename($0);
+  my $SELF = catfile $FindBin::Bin, $script;
+  
+  # POSIX unmasks the sigprocmask properly
+  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";
+      }
+  }
+  __END__
+
+
 =head1 Named Pipes
 
 A named pipe (often referred to as a FIFO) is an old Unix IPC
@@ -206,40 +279,101 @@ to find out whether anyone (or anything) has accidentally removed our fifo.
        sleep 2;    # to avoid dup signals
     }
 
-=head2 WARNING
+=head2 Deferred Signals
 
-By installing Perl code to deal with signals, you're 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.
+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 are two things you can do, knowing this: be paranoid or be
-pragmatic.  The paranoid approach is to do as little as possible in your
+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 C<die> to longjump(3) out
 of the handler.  Even this is a little cavalier for the true paranoiac,
 who avoids C<die> in a handler because the system I<is> out to get you.
-The pragmatic approach is to say ``I know the risks, but prefer the
-convenience'', and to do anything you want in your signal handler,
-prepared to clean up core dumps now and again.
-
-To forbid signal handlers altogether would bars you from
-many interesting programs, including virtually everything in this manpage,
-since you could no longer even write SIGCHLD handlers.  Their dodginess
-is expected to be addresses in the 5.005 release.
+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:
+
+=over 4
+
+=item Long running opcodes
+
+As Perl interpreter only looks at the signal flags when it about to
+execute a new opcode if a signal arrives during a long running opcode
+(e.g. a regular expression operation on a very large string) then
+signal will not be seen until operation completes.
+
+=item Interrupting IO
+
+When a signal is delivered (e.g. INT control-C) the operating system
+breaks into IO operations like C<read> (used to implement Perls
+E<lt>E<gt> operator). On older Perls the handler was called
+immediately (and as C<read> is not "unsafe" this worked well). With
+the "deferred" scheme the handler is not called immediately, and if
+Perl is using system's C<stdio> library that library may re-start the
+C<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
+C<:perlio> layer to do IO - at least on those handles which you want
+to be able to break into with signals. (The C<: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 C<:perlio> layer.
+
+=item Signals as "faults"
+
+Certain signals e.g. SEGV, ILL, 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. (In particular the
+old signal scheme was particularly unsafe in such cases.)  However if
+a %SIG handler is set the new scheme simply sets a flag and returns as
+described above. This may cause the operating system to try the
+offending machine instruction again and - as nothing has changed - it
+will generate the signal again. The result of this is a rather odd
+"loop". In future Perl's signal mechanism may be changed to avoid this
+- perhaps by simply disallowing %SIG handlers on signals of that
+type. Until then the work-round is not to set a %SIG handler on those
+signals. (Which signals they are is operating system dependant.)
+
+=item 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 C<wait> for the completed child
+process. On such systems the deferred signal scheme will not work for
+those signals (it does not do the C<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.
 
+=back
 
 =head1 Using open() for IPC
 
-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:
+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: $!";
@@ -367,7 +501,7 @@ write to the filehandle you opened and your kid will find it in his
 STDIN.  If you open a pipe I<from> minus, you can read from the filehandle
 you opened whatever your kid writes to his STDOUT.
 
-    use English;
+    use English '-no_match_vars';
     my $sleep_count = 0;
 
     do {
@@ -449,8 +583,8 @@ doesn't actually work:
 
     open(PROG_FOR_READING_AND_WRITING, "| some program |")
 
-and if you forget to use the B<-w> flag, then you'll miss out
-entirely on the diagnostic message:
+and if you forget to use the C<use warnings> pragma or the B<-w> flag,
+then you'll miss out entirely on the diagnostic message:
 
     Can't do bidirectional pipe at -e line 1.
 
@@ -504,7 +638,7 @@ in the SEE ALSO section below.
 The newer Expect.pm module from CPAN also addresses this kind of thing.
 This module requires two other modules from CPAN: IO::Pty and IO::Stty.
 It sets up a pseudo-terminal to interact with programs that insist on
-using talking to the terminal device driver.  If your system is 
+using talking to the terminal device driver.  If your system is
 amongst those supported, this may be your best bet.
 
 =head2 Bidirectional Communication with Yourself
@@ -540,7 +674,7 @@ handles to STDIN and STDOUT and call other processes.
        exit;
     }
 
-But you don't actually have to make two pipe calls.  If you 
+But you don't actually have to make two pipe calls.  If you
 have the socketpair() system call, it will do this all for you.
 
     #!/usr/bin/perl -w
@@ -657,13 +791,14 @@ instead.
     BEGIN { $ENV{PATH} = '/usr/ucb:/bin' }
     use Socket;
     use Carp;
-    $EOL = "\015\012";
+    my $EOL = "\015\012";
 
     sub logmsg { print "$0 $$: @_ at ", scalar localtime, "\n" }
 
     my $port = shift || 2345;
     my $proto = getprotobyname('tcp');
-    $port = $1 if $port =~ /(\d+)/; # untaint port number
+
+    ($port) = $port =~ /^(\d+)$/                        or die "invalid port";
 
     socket(Server, PF_INET, SOCK_STREAM, $proto)       || die "socket: $!";
     setsockopt(Server, SOL_SOCKET, SO_REUSEADDR,
@@ -699,14 +834,15 @@ go back to service a new client.
     BEGIN { $ENV{PATH} = '/usr/ucb:/bin' }
     use Socket;
     use Carp;
-    $EOL = "\015\012";
+    my $EOL = "\015\012";
 
     sub spawn;  # forward declaration
     sub logmsg { print "$0 $$: @_ at ", scalar localtime, "\n" }
 
     my $port = shift || 2345;
     my $proto = getprotobyname('tcp');
-    $port = $1 if $port =~ /(\d+)/; # untaint port number
+
+    ($port) = $port =~ /^(\d+)$/                        or die "invalid port";
 
     socket(Server, PF_INET, SOCK_STREAM, $proto)       || die "socket: $!";
     setsockopt(Server, SOL_SOCKET, SO_REUSEADDR,
@@ -719,10 +855,13 @@ go back to service a new client.
     my $waitedpid = 0;
     my $paddr;
 
+    use POSIX ":sys_wait_h";
     sub REAPER {
-       $waitedpid = wait;
+       my $child;
+        while (($waitedpid = waitpid(-1,WNOHANG)) > 0) {
+           logmsg "reaped $waitedpid" . ($? ? " with exit $?" : '');
+       }
        $SIG{CHLD} = \&REAPER;  # loathe sysV
-       logmsg "reaped $waitedpid" . ($? ? " with exit $?" : '');
     }
 
     $SIG{CHLD} = \&REAPER;
@@ -740,6 +879,7 @@ go back to service a new client.
                at port $port";
 
        spawn sub {
+           $|=1;
            print "Hello there, $name, it's now ", scalar localtime, $EOL;
            exec '/usr/games/fortune'           # XXX: `wrong' line terminators
                or confess "can't exec fortune: $!";
@@ -831,7 +971,7 @@ domain sockets can show up in the file system with an ls(1) listing.
 You can test for these with Perl's B<-S> file test:
 
     unless ( -S '/dev/log' ) {
-       die "something's wicked with the print system";
+       die "something's wicked with the log system";
     }
 
 Here's a sample Unix-domain client:
@@ -859,6 +999,7 @@ to be on the localhost, and thus everything works right.
     use Carp;
 
     BEGIN { $ENV{PATH} = '/usr/ucb:/bin' }
+    sub spawn;  # forward declaration
     sub logmsg { print "$0 $$: @_ at ", scalar localtime, "\n" }
 
     my $NAME = '/tmp/catsock';
@@ -874,10 +1015,13 @@ to be on the localhost, and thus everything works right.
 
     my $waitedpid;
 
+    use POSIX ":sys_wait_h";
     sub REAPER {
-       $waitedpid = wait;
+       my $child;
+        while (($waitedpid = waitpid(-1,WNOHANG)) > 0) {
+           logmsg "reaped $waitedpid" . ($? ? " with exit $?" : '');
+       }
        $SIG{CHLD} = \&REAPER;  # loathe sysV
-       logmsg "reaped $waitedpid" . ($? ? " with exit $?" : '');
     }
 
     $SIG{CHLD} = \&REAPER;
@@ -895,6 +1039,29 @@ to be on the localhost, and thus everything works right.
        };
     }
 
+    sub spawn {
+       my $coderef = shift;
+
+       unless (@_ == 0 && $coderef && ref($coderef) eq 'CODE') {
+           confess "usage: spawn CODEREF";
+       }
+
+       my $pid;
+       if (!defined($pid = fork)) {
+           logmsg "cannot fork: $!";
+           return;
+       } elsif ($pid) {
+           logmsg "begat $pid";
+           return; # I'm the parent
+       }
+       # else I'm the child -- go spawn
+
+       open(STDIN,  "<&Client")   || die "can't dup client to stdin";
+       open(STDOUT, ">&Client")   || die "can't dup client to stdout";
+       ## open(STDERR, ">&STDOUT") || die "can't dup stdout to stderr";
+       exit &$coderef();
+    }
+
 As you see, it's remarkably similar to the Internet domain TCP server, so
 much so, in fact, that we've omitted several duplicate functions--spawn(),
 logmsg(), ctime(), and REAPER()--which are exactly the same as in the
@@ -918,7 +1085,7 @@ For those preferring a higher-level interface to socket programming, the
 IO::Socket module provides an object-oriented approach.  IO::Socket is
 included as part of the standard Perl distribution as of the 5.004
 release.  If you're running an earlier version of Perl, just fetch
-IO::Socket from CPAN, where you'll also find find modules providing easy
+IO::Socket from CPAN, where you'll also find modules providing easy
 interfaces to the following systems: DNS, FTP, Ident (RFC 931), NIS and
 NISPlus, NNTP, Ping, POP3, SMTP, SNMP, SSLeay, Telnet, and Time--just
 to name a few.
@@ -946,7 +1113,7 @@ looks like this:
 
 Here are what those parameters to the C<new> constructor mean:
 
-=over
+=over 4
 
 =item C<Proto>
 
@@ -1018,9 +1185,9 @@ something to the server before fetching the server's response.
     }
 
 The web server handing the "http" service, which is assumed to be at
-its standard port, number 80.  If your the web server you're trying to
+its standard port, number 80.  If the web server you're trying to
 connect to is at a different port (like 1080 or 8080), you should specify
-as the named-parameter pair, C<PeerPort =E<gt> 8080>.  The C<autoflush>
+as the named-parameter pair, C<< PeerPort => 8080 >>.  The C<autoflush>
 method is used on the socket because otherwise the system would buffer
 up the output we sent it.  (If you're on a Mac, you'll also need to
 change every C<"\n"> in your code that sends data over the network to
@@ -1138,10 +1305,10 @@ well.
 As always, setting up a server is little bit more involved than running a client.
 The model is that the server creates a special kind of socket that
 does nothing but listen on a particular port for incoming connections.
-It does this by calling the C<IO::Socket::INET-E<gt>new()> method with
+It does this by calling the C<< IO::Socket::INET->new() >> method with
 slightly different arguments than the client did.
 
-=over
+=over 4
 
 =item Proto
 
@@ -1178,8 +1345,8 @@ clear out.
 
 Once the generic server socket has been created using the parameters
 listed above, the server then waits for a new client to connect
-to it.  The server blocks in the C<accept> method, which eventually an
-bidirectional connection to the remote client.  (Make sure to autoflush
+to it.  The server blocks in the C<accept> method, which eventually accepts a
+bidirectional connection from the remote client.  (Make sure to autoflush
 this handle to circumvent buffering.)
 
 To add to user-friendliness, our server prompts the user for commands.
@@ -1241,6 +1408,11 @@ find yourself overly concerned about reliability and start building checks
 into your message system, then you probably should use just TCP to start
 with.
 
+Note that UDP datagrams are I<not> a bytestream and should not be treated
+as such. This makes using I/O mechanisms with internal buffering
+like stdio (i.e. print() and friends) especially cumbersome. Use syswrite(),
+or better send(), like in the example below.
+
 Here's a UDP program similar to the sample Internet TCP client given
 earlier.  However, instead of checking one host at a time, the UDP version
 will check many of them asynchronously by simulating a multicast and then
@@ -1291,6 +1463,11 @@ with TCP, you'd have to use a different socket handle for each host.
        $count--;
     }
 
+Note that this example does not include any retries and may consequently
+fail to contact a reachable host. The most prominent reason for this
+is congestion of the queues on the sending host if the number of
+list of hosts to contact is sufficiently large.
+
 =head1 SysV IPC
 
 While System V IPC isn't so widely used as sockets, it still has some
@@ -1301,16 +1478,16 @@ you weren't wanting it to.
 
 Here's a small example showing shared memory usage.
 
-    use IPC::SysV qw(IPC_PRIVATE IPC_RMID S_IRWXU S_IRWXG S_IRWXO);
+    use IPC::SysV qw(IPC_PRIVATE IPC_RMID S_IRWXU);
 
     $size = 2000;
-    $key = shmget(IPC_PRIVATE, $size, S_IRWXU|S_IRWXG|S_IRWXO) || die "$!";
-    print "shm key $key\n";
+    $id = shmget(IPC_PRIVATE, $size, S_IRWXU) || die "$!";
+    print "shm key $id\n";
 
     $message = "Message #1";
-    shmwrite($key, $message, 0, 60) || die "$!";
+    shmwrite($id, $message, 0, 60) || die "$!";
     print "wrote: '$message'\n";
-    shmread($key, $buff, 0, 60) || die "$!";
+    shmread($id, $buff, 0, 60) || die "$!";
     print "read : '$buff'\n";
 
     # the buffer of shmread is zero-character end-padded.
@@ -1318,16 +1495,16 @@ Here's a small example showing shared memory usage.
     print "un" unless $buff eq $message;
     print "swell\n";
 
-    print "deleting shm $key\n";
-    shmctl($key, IPC_RMID, 0) || die "$!";
+    print "deleting shm $id\n";
+    shmctl($id, IPC_RMID, 0) || die "$!";
 
 Here's an example of a semaphore:
 
     use IPC::SysV qw(IPC_CREAT);
 
     $IPC_KEY = 1234;
-    $key = semget($IPC_KEY, 10, 0666 | IPC_CREAT ) || die "$!";
-    print "shm key $key\n";
+    $id = semget($IPC_KEY, 10, 0666 | IPC_CREAT ) || die "$!";
+    print "shm key $id\n";
 
 Put this code in a separate file to be run in more than one process.
 Call the file F<take>:
@@ -1335,8 +1512,8 @@ Call the file F<take>:
     # create a semaphore
 
     $IPC_KEY = 1234;
-    $key = semget($IPC_KEY,  0 , 0 );
-    die if !defined($key);
+    $id = semget($IPC_KEY,  0 , 0 );
+    die if !defined($id);
 
     $semnum = 0;
     $semflag = 0;
@@ -1344,14 +1521,14 @@ Call the file F<take>:
     # 'take' semaphore
     # wait for semaphore to be zero
     $semop = 0;
-    $opstring1 = pack("sss", $semnum, $semop, $semflag);
+    $opstring1 = pack("s!s!s!", $semnum, $semop, $semflag);
 
     # Increment the semaphore count
     $semop = 1;
-    $opstring2 = pack("sss", $semnum, $semop,  $semflag);
+    $opstring2 = pack("s!s!s!", $semnum, $semop,  $semflag);
     $opstring = $opstring1 . $opstring2;
 
-    semop($key,$opstring) || die "$!";
+    semop($id,$opstring) || die "$!";
 
 Put this code in a separate file to be run in more than one process.
 Call this file F<give>:
@@ -1361,22 +1538,53 @@ Call this file F<give>:
     # that the second process continues
 
     $IPC_KEY = 1234;
-    $key = semget($IPC_KEY, 0, 0);
-    die if !defined($key);
+    $id = semget($IPC_KEY, 0, 0);
+    die if !defined($id);
 
     $semnum = 0;
     $semflag = 0;
 
     # Decrement the semaphore count
     $semop = -1;
-    $opstring = pack("sss", $semnum, $semop, $semflag);
+    $opstring = pack("s!s!s!", $semnum, $semop, $semflag);
 
-    semop($key,$opstring) || die "$!";
+    semop($id,$opstring) || die "$!";
 
 The SysV IPC code above was written long ago, and it's definitely
 clunky looking.  For a more modern look, see the IPC::SysV module
 which is included with Perl starting from Perl 5.005.
 
+A small example demonstrating SysV message queues:
+
+    use IPC::SysV qw(IPC_PRIVATE IPC_RMID IPC_CREAT S_IRWXU);
+
+    my $id = msgget(IPC_PRIVATE, IPC_CREAT | S_IRWXU);
+
+    my $sent = "message";
+    my $type = 1234;
+    my $rcvd;
+    my $type_rcvd;
+
+    if (defined $id) {
+        if (msgsnd($id, pack("l! a*", $type_sent, $sent), 0)) {
+            if (msgrcv($id, $rcvd, 60, 0, 0)) {
+                ($type_rcvd, $rcvd) = unpack("l! a*", $rcvd);
+                if ($rcvd eq $sent) {
+                    print "okay\n";
+                } else {
+                    print "not okay\n";
+                }
+            } else {
+                die "# msgrcv failed\n";
+            }
+        } else {
+            die "# msgsnd failed\n";
+        }
+        msgctl($id, IPC_RMID, 0) || die "# msgctl failed: $!\n";
+    } else {
+        die "# msgget failed\n";
+    }
+
 =head1 NOTES
 
 Most of these routines quietly but politely return C<undef> when they
@@ -1407,7 +1615,7 @@ little else within a handler beyond setting a numeric variable that
 already exists; or, if locked into a slow (restarting) system call,
 using die() to raise an exception and longjmp(3) out.  In fact, even
 these may in some cases cause a core dump.  It's probably best to avoid
-signals except where they are absolutely inevitable.  This 
+signals except where they are absolutely inevitable.  This
 will be addressed in a future release of Perl.
 
 =head1 AUTHOR