Perl sigaction(SIGALRM,...) and gethostbyname

Perl sigaction(SIGALRM,...) and gethostbyname

Post by Joe Schaefe » Fri, 09 Nov 2001 10:56:29



Here's a Perl script that does 5 hostname lookups via
gethostbyname() which is wrapped in a 2 second alarm.
The problem is that once the alarm is triggered, *all*
subsequent lookups are failing.  Short of writing a C
analog that produces a similar set of system calls,
I'm really having trouble understanding why this is
happening.

Here's the code, a sample run, and a stack trace
("www.rgee.com" is the first one that fails here):

  % cat try.pl
  #!/usr/bin/perl -w
  use POSIX qw/:signal_h/;

  sub alrm {die "timeout"}
  use constant FLAGS => 0;         # SA_RESTART; #SA_RESETHAND;# ???

  # set up the requisite Perl objects for sigaction a'la POSIX manpage
  $sigset = POSIX::SigSet->new(SIGALRM);
  $sigact = POSIX::SigAction->new("main::alrm", $sigset, FLAGS);

  for (<DATA>) {
    chomp;

    eval {                            # trap the alarm
        sigaction(SIGALRM, $sigact);  # install the signal handler
        alarm 2;
        $addr = gethostbyname $_;     # kaboom
        alarm 0;
    };


    else {
        $addr = $addr ? join '.', unpack('C4', $addr) : "BZZT";
        print "$_ => $addr\n";
    }
  }

  __END__
  www.microsoft.com
  www.aol.com
  www.rgee.com
  www.aol.com
  www.microsoft.com

  % ./try.pl
  www.microsoft.com => 207.46.230.220
  www.aol.com => 64.12.149.24
  www.rgee.com => timeout at /tmp/try.pl line 4, <DATA> line 83.
  www.aol.com => timeout at /tmp/try.pl line 4, <> line 83.
  www.microsoft.com => timeout at /tmp/try.pl line 4, <> line 83.

  % strace ./try.pl
  ...
  send(5, "<\233\1\0\0\1\0\0\0\0\0\0\3www\4rgee\3com\0\0\1\0\1", 30, 0) = 30
  gettimeofday({1003909154, 795857}, NULL) = 0
  poll([{fd=5, events=POLLIN}], 1, 5000)  = -1 EINTR (Interrupted system call)
  --- SIGALRM (Alarm clock) ---
  rt_sigprocmask(SIG_SETMASK, [RT_0], NULL, 8) = 0
  write(1, "www.rgee.com => timeout at /tmp/"...,) = 58
  write(1, "\n", 1
  )                       = 1
  rt_sigaction(SIGALRM, {0x40065f70, [], SA_RESTART|0x4000000},
                        {0x40065f70, [], 0x4000000}, 8) = 0
  rt_sigaction(SIGALRM, {0x40065f70, [], 0x4000000}, NULL, 8) = 0
  alarm(2)                                = 0
  rt_sigprocmask(SIG_SETMASK, NULL, [RT_0], 8) = 0
  rt_sigsuspend([] <unfinished ...>
  --- SIGALRM (Alarm clock) ---
  <... rt_sigsuspend resumed> )           = -1 EINTR (Interrupted system call)
  rt_sigprocmask(SIG_SETMASK, [RT_0], NULL, 8) = 0
  write(1, "www.aol.com => timeout at /tmp/t"...,) = 57
  write(1, "\n", 1
  )                       = 1
  rt_sigaction(SIGALRM, {0x40065f70, [], SA_RESTART|0x4000000},
                        {0x40065f70, [], 0x4000000}, 8) = 0
  rt_sigaction(SIGALRM, {0x40065f70, [], 0x4000000}, NULL, 8) = 0
  alarm(2)                                = 0
  rt_sigprocmask(SIG_SETMASK, NULL, [RT_0], 8) = 0
  rt_sigsuspend([] <unfinished ...>
  --- SIGALRM (Alarm clock) ---
  ...

The code misbehaves as above for Perl versions 5.00503 and up, and
both 2.2 and 2.4 linux kernels.  However, it apparently works fine
on Solaris (the subsequent gethostbyname calls work ok even after the
alarm goes off).

I've tried coding it using various flags for sigaction (SA_RESTART,
SA_RESETHAND, ...) but the behavior remains unchanged. I originally
asked this question a week or so ago in clp.misc, but nobody there
provided an explanation for this behavior. I'm obviously missing
something; can anyone help me out here?

--
Joe Schaefer

 
 
 

Perl sigaction(SIGALRM,...) and gethostbyname

Post by Ilja Tabachni » Fri, 09 Nov 2001 17:05:34



> Here's a Perl script that does 5 hostname lookups via
> gethostbyname() which is wrapped in a 2 second alarm.
> The problem is that once the alarm is triggered, *all*
> subsequent lookups are failing.  Short of writing a C
> analog that produces a similar set of system calls,
> I'm really having trouble understanding why this is
> happening.

<...skipped...>

Quote:> The code misbehaves as above for Perl versions 5.00503 and up, and
> both 2.2 and 2.4 linux kernels.  However, it apparently works fine
> on Solaris (the subsequent gethostbyname calls work ok even after the
> alarm goes off).

Hm-m, looks functional for me:

$ uname -a
Linux iljat 2.2.19 #22 Wed Jun 20 18:12:16 PDT 2001 i586 unknown
$ perl -v
This is perl, v5.6.1 built for i386-linux
$ ./r
www.microsoft.com => 207.46.230.219
www.aol.com => 64.12.149.24
www.rgee.com => timeout at ./r line 7, <DATA> line 5.
www.aol.com => 205.188.160.121
www.microsoft.com => 207.46.197.113

Ilja.

 
 
 

Perl sigaction(SIGALRM,...) and gethostbyname

Post by Andrew Giert » Fri, 09 Nov 2001 18:02:57


 Joe> Here's a Perl script that does 5 hostname lookups via
 Joe> gethostbyname() which is wrapped in a 2 second alarm.  The
 Joe> problem is that once the alarm is triggered, *all* subsequent
 Joe> lookups are failing.

You are interrupting a signal-unsafe function with a signal,
longjmping (via perl's die()) out of the signal handler, and then
calling more signal-unsafe functions. This doesn't even work in C,
let alone Perl.

There is no (reliable|portable) way to impose a timeout on
gethostbyname() using signals.

--
Andrew.

comp.unix.programmer FAQ: see <URL: http://www.erlenstar.demon.co.uk/unix/>
                           or <URL: http://www.whitefang.com/unix/>

 
 
 

Perl sigaction(SIGALRM,...) and gethostbyname

Post by Joe Schaefe » Sat, 10 Nov 2001 02:40:33



> Hm-m, looks functional for me:

> $ uname -a
> Linux iljat 2.2.19 #22 Wed Jun 20 18:12:16 PDT 2001 i586 unknown
> $ perl -v
> This is perl, v5.6.1 built for i386-linux
> $ ./r
> www.microsoft.com => 207.46.230.219
> www.aol.com => 64.12.149.24
> www.rgee.com => timeout at ./r line 7, <DATA> line 5.
> www.aol.com => 205.188.160.121
> www.microsoft.com => 207.46.197.113

My glibc rpm is glibc-2.1.92-14; I think it's glibc that is causing the
differing behaviors.  Could you post or email me the stack trace you
got?  I've looked for an explanation in the glibc info documentation;
in particular the node "Primitives Interrupted by Signals", but I can't
make heads or tails of whether my box's attempt to resume a suspended
call are correct given the poll()'s EINTR return value.

--
Joe Schaefer

 
 
 

1. SIGACTION works with SIGALRM but not others

I have a piece of code that works fine with SIGALRM

        actNew . sa_handler = handle_sigalrm ;
        actNew . sa_flags = SA_RESTART ;
        if ( sigaction ( SIGALRM, & actNew, & actOld ) != 0 )
                exit(-1) ;

When I do "ps" -> see <pid> -> "kill -s SIGALRM <pid>
I get control at "handle_sigalrm". Nice. SO far, so good.

But if we change SIGALRM to SIGUSR1 or SIGUSR2 or SIGSYS or SIGHUP,
we do NOT get control. Why ?

Just give me a pointer, please. Sebastian.

2. strangely serial Problem

3. SIGALRM while in SIGALRM handler

4. SCO w/ more than 10 users

5. tcpwrappers gethostbyname fails, works in Perl

6. Help needed with fdisk

7. Matrox Mystique ands X.

8. Using floppy tape drive.

9. Perl developer/Unix SA turns PM and selling Library of unix/linux/perl books

10. /usr/local/bin/perl ->/usr/bin/perl

11. UPDATE: Compiling GTK/Perl with Perl 5.004 on Solaris

12. Apache-perl: place html files and perl scripts in the same location

13. #!/usr/bin/perl or #!usr/bin/perl