[comp.lang.perl] Perl dies when using SIGIO

marcl@ESD.3Com.COM (Marc Lavine) (03/09/91)

I've been fiddling around with some Perl code to do asynchronous
network I/O using SIGIO.  I've been running this on a Sparcstation SLC
under SunOS 4.1.1.  I'm having problems with Perl dying in a variety
of ways.  I suspect that this is a reentrancy problem.  I started with
Perl 3.0.44 and then switched to 4.0.beta.  Malloc seemed like a
probable culprit (since malloc is likely to be used inside my SIGIO
handler), so I rebuilt perl with GNU malloc (which is supposed to be
reentrant).  This changed the symptoms slightly (Perl would often get
an abort rather than a segmentation violation or bus error).  The
problem also shows up using Sun malloc's and Perl's own malloc.
Sometimes it would die with "panic: restorelist inconsistency".  I'm
enclosing a Perl script that should make it possible for others to
reproduce this problem.  To see the problem, just feed sigio.pl a file
with one hostname per line (such as the enclosed "hosts" file).  It
will create a bunch of connections to the hosts' SMTP ports and if
your environment has the same problem as mine, it will eventually die
(although, I suppose you might need to feed it more hostnames than are
in my sample file).  Am I trying to do the impossible with Perl or
have I simply run into a bug?


#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of shell archive."
# Contents:  sigio.pl hosts
# Wrapped by marcl@cook.ESD.3Com.COM on Fri Mar  8 18:27:03 1991
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'sigio.pl' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'sigio.pl'\"
else
echo shar: Extracting \"'sigio.pl'\" \(3846 characters\)
sed "s/^X//" >'sigio.pl' <<'END_OF_FILE'
X#!/usr/local/bin/perl --    # -*-Perl-*-
X#
X# Experiments with networking in perl.
X#
X
X$debug_printing = 1;
X
Xrequire "sys/socket.ph";
Xrequire "fcntl.ph";
Xrequire "errno.ph";
Xrequire "ctime.pl";
X
Xchop ( $ourhostname = `hostname` );
X$sockaddr = 'S n a4 x8';
X$SIG{'IO'} = 'SIGIO_Handler';
X$sock_select_mask = '';
X
Xwhile ( <> )
X{
X    chop;
X    &Initiate_Connection ( $_, "smtp" );
X}
X
Xsleep ( 20 );
X
X
Xsub debug_print
X    {
X    if ( $debug_printing )
X	{
X	print @_;
X	}
X    }
X
X
X# SIGIO signal handler
Xsub SIGIO_Handler
X    {
X    &debug_print ( "SIGIO_Handler entered\n" );
X    local ( $sock, $data );
X    local ( $timeout ) = 0;
X    local ( $read_mask ) = $sock_select_mask;
X    local ( @ready_socks );
X    local ( $bytes_read, $result );
X
X    local ( $nfound ) = select ( $read_mask, undef, undef, 0 );
X    if ( $nfound == -1 )
X	{
X	warn "select: $!";
X	}
X    else
X	{
X	&debug_print ( $nfound, " handles ready for reading\n" );
X	}
X
X    @ready_socks = grep ( vec ( $read_mask, fileno ( $_ ), 1 ),
X	values ( %handles_by_number ) );
X
X    foreach $sock ( @ready_socks )
X	{
X	# Socket has pending input
X	$result = recv ( $sock, $data, 1024, 0 );
X	if ( !defined ( $result ) )
X	    {
X	    print ( "Error talking to ",
X		   $sock_hostname { $sock }, ": ",  $!, "\n" );
X	    &Terminate_Connection ( $sock );
X	    }
X	else
X	    {
X	    &debug_print ( "Read " . length ( $data ) . " bytes from ",
X	        $sock_hostname { $sock }, ":\n" );
X	    print $data;
X	    }
X	}
X
X    &debug_print ( "SIGIO_Handler done\n" );
X    }
X
X
X# Create a connection to the specified host and port.
Xsub Initiate_Connection
X    {
X    &debug_print ( "Initiate_Connection entered\n" );
X    local ( $host ) = $_[0];
X    local ( $port ) = $_[1];
X    local ( $result, $localaddr, $rmtaddr, $localsock, $rmtsock );
X    local ( $name, $aliases, $proto, $rmtport, $len );
X    local ( $sock ) = sprintf ( "SOCK.%d", $sock_counter++ );
X
X    &debug_print ( $_[0], ":\n" );
X
X    ( $name, $aliases, $proto ) = getprotobyname ( "tcp" );
X    ( $name, $aliases, $rmtport ) = getservbyname ( $port, "tcp" )
X	unless $port =~ /^\d+$/;
X    ( $name, $aliases, $type, $len, $localaddr ) =
X	gethostbyname ( $ourhostname );
X    if ( !( ( $name, $aliases, $type, $len, $rmtaddr )
X	   = gethostbyname ( $host ) ) )
X	{
X	print ( "Can't get address for ", $host, "\n" );
X	return;
X	}
X
X    $localsock = pack ( $sockaddr, &AF_INET, 0, $localaddr );
X    $rmtsock = pack ( $sockaddr, &AF_INET, $rmtport, $rmtaddr );
X
X    while ( !( $result = socket ( $sock, &AF_INET, &SOCK_STREAM, $proto ) ) )
X	{
X	if ( $result == &EMFILE )
X	    {
X	    # Wait for an existing socket to be closed.
X	    &debug_print ( "Waiting for a socket...\n" );
X	    sleep ( 1 );
X	    }
X	else
X	    {
X	    die "socket: $!";
X	    }
X	}
X
X    local ( $sockno ) = fileno ( $sock );
X    $handles_by_number { $sockno } = $sock;
X    $sock_hostname { $sock } = $name;
X    vec ( $sock_select_mask, $sockno, 1 ) = 1;
X    &debug_print ( "Socket file number=", $sockno, "\n" );
X    
X    fcntl ( $sock, &F_SETOWN, $$ ) || die "fcntl (set owner): $!";
X    fcntl ( $sock, &F_SETFL, &FNDELAY | &FASYNC ) || die "fcntl: $!";
X    &debug_print ( "Fcntls done.\n" );
X    bind ( $sock, $localsock ) || die "bind: $!";
X    &debug_print ( "Bind done.\n" );
X
X    ( $result = connect ( $sock, $rmtsock ) ) || ( $! == &EINPROGRESS )
X	|| die "connect: $!";
X    &debug_print ( "Connect done.\n" );
X
X    &debug_print ( "Initiate_Connection done\n" );
X    }
X
X
X# Destroy the specified connection.
Xsub Terminate_Connection
X    {
X    &debug_print ( "Terminate_Connection entered\n" );
X    local ( $sock ) = $_[0];
X
X    local ( $sockno ) = fileno ( $sock );
X    vec ( $sock_select_mask, $sockno, 1 ) = 0;
X    shutdown ( $sock, 2 );
X    close ( $sock );
X
X    undef $handles_by_number { $sockno };
X    undef $sock_hostname { $sock };
X    
X    &debug_print ( "Terminate_Connection done\n" );
X    }
END_OF_FILE
if test 3846 -ne `wc -c <'sigio.pl'`; then
    echo shar: \"'sigio.pl'\" unpacked with wrong size!
fi
chmod +x 'sigio.pl'
# end of 'sigio.pl'
fi
if test -f 'hosts' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'hosts'\"
else
echo shar: Extracting \"'hosts'\" \(200 characters\)
sed "s/^X//" >'hosts' <<'END_OF_FILE'
Xlocalhost
Xlocalhost
Xlocalhost
Xlocalhost
Xlocalhost
Xlocalhost
Xlocalhost
Xlocalhost
Xlocalhost
Xlocalhost
Xlocalhost
Xlocalhost
Xlocalhost
Xlocalhost
Xlocalhost
Xlocalhost
Xlocalhost
Xlocalhost
Xlocalhost
Xlocalhost
END_OF_FILE
if test 200 -ne `wc -c <'hosts'`; then
    echo shar: \"'hosts'\" unpacked with wrong size!
fi
# end of 'hosts'
fi
echo shar: End of shell archive.
exit 0
--
Marc Lavine		    	Broken: marcl%3Com.Com@sun.com
Smart: marcl@3Com.Com	    	UUCP: ...{sun|decwrl}!3Com.Com!marcl