Operating System - OpenVMS
1824822 Members
4378 Online
109674 Solutions
New Discussion юеВ

Perl alarms don't work on VMS

 
SOLVED
Go to solution
Tim Yeung_1
Frequent Advisor

Perl alarms don't work on VMS

See attached perl script. It creates a network port and waits for connections. It is suppose to time out in 30 seconds. The program works on Linux and on HPUX. But doesn't work on VMS. It never times out on VMS.

On Linux:

# perl setalarm.pl
setting alarm
1. process timed out at setalarm.pl line 10.
closing socket


On VMS (perl 5.8.6 with ECO1):
$ perl setalarm.pl
setting alarm


Also posted in cpan forum
5 REPLIES 5
Robert Atkinson
Respected Contributor
Solution

Re: Perl alarms don't work on VMS

Tim, it might be worth contacting Craig Berry (Perl VMS porting), or ask at the perl.vmsperl Usenet for this one.

I know Craig monitors the ITRC, so may stick his head above the wall.

His email is 'craigberry at mac dot com'

Rob.
Willem Grooters
Honored Contributor

Re: Perl alarms don't work on VMS

FWIW: Tried this on a Windows box Perl 5.7.1, and it didn't timeout either (assuming it should timeout in 30 seconds?).

(PLEASE do NOT post files in this matter. To be sure it'll be opened as an ASCII file, give it a 'harmless' extension like .TXT)

WG
Willem Grooters
OpenVMS Developer & System Manager
Hein van den Heuvel
Honored Contributor

Re: Perl alarms don't work on VMS

Wim, a .pl extention works fine oon my system. Goes straight to Crimson Editor! But I agree, it would be nice if folks posted attachements with simple .TXT extentions.

Tim,

Perl alarms do work, just not in all circumstances you expect them to work.

Like they will not kill an active "system" call, but they will trigger when that returns.
CRaig will surely provide details.
In the mean time please find below two runs for a simple test and a perl 'program' loosely based on your code but using a 'system' tasks.

my $loopcount = shift // 10;
my $seconds = shift // 3;
eval {
local $SIG{ALRM} = sub { die "process timed out"; };
print "setting alarm\n";
alarm 10;
eval {

for (1..$loopcount) {
print "$_\n";
system ("wait 0:0:$seconds" );
}
};
alarm 0;
print "1. $@\n" if ($@);
};

alarm 0;
print "2. $@\n" if ($@);

print "closing socket\n";

close ($server);


$ perl tmp1.pl
setting alarm
1
2
3
4
1. process timed out at tmp1.pl line 4.

closing socket

$ perl tmp1.pl 3 1
setting alarm
1
2
3
closing socket


$ perl -v

This is perl, v5.8.8 built for VMS_IA64
(with 1 registered patch, see perl -V for more detail)

:
$ perl "-V"
Summary of my perl5 (revision 5 version 8 subversion 8) configuration:
Platform:
osname=VMS, osvers=V8.3, archname=VMS_IA64
:
Locally applied patches:
defined-or


note:
The // operator used is the 'defined-or'
If your perl does not have this, then use something like:

my $loopcount = shift;
$loopcount = 10 unless $loopcount;
Craig A Berry
Honored Contributor

Re: Perl alarms don't work on VMS

Imagine a picture of me sticking my head above the wall.

I guess the first thing to understand here is that Perl's default signal handling mechanism (so-called "safe" or, more properly, "deferred" signals) doesn't allow signal delivery while a Perl opcode is running. With the exception of fatal signals that are expected to bring down the interpreter, a signal is caught, a counter bumped, and then it is ignored until the current opcode finishes (an opcode being an "instruction" on the Perl virtual machine). During the transition from one opcode to the next, the counters are checked, the handlers for any signals that have been deferred are called explicitly, and the counters are zeroed. From a VMS point of view, your signal handlers don't end up executing at AST level.

As I understand it the reason for this is that opcode transitions are done with longjmp(), i.e., stack manipulation, and you really don't want to be fiddling with the stack while you are executing a signal handler. Basically Perl takes control of when it runs your signal handler so that it's not jumping around the stack while the handler is running.

So, why does this matter? For short-running opcodes it really doesn't. But for long-running opcodes, i.e., longer than your alarm interval, it can be surprising. Particularly if the Perl opcode boils down to a long-running syscall like accept() or select(), it may seem like the alarm never fires, when in fact it does but is deferred. You can even flood the signal queue and end up getting an ASTFLT error if you have hundreds or thousands of signals fire during one opcode. I've discussed some of this elsewhere:

http://www.xray.mpe.mpg.de/mailing-lists/perl5-porters/2007-02/msg00949.html

The apparent difference with Linux is that the alarm causes the accept() call to terminate, most likely with EINTR. When the sycall terminates, the Perl opcode completes, deferred signals are delivered, and off you go. VMS (and apparently Windows) don't do that, i.e., the accept() doesn't terminate when the alarm fires; they expect the signal handler to be off doing its thing while they continue to do theirs. In a C program with signals enabled, that would work, but because Perl defers the signals, you end up blocking. As far as I know, no standard governs this and both behaviors are kosher, just different.

All of the foregoing explains why the alarm doesn't fire at 10 seconds. It does not explain why the accept() does not time out after 30 seconds, which is completely unrelated. The reason the accept() does not time out is that you have not set a timeout value (the Listen parameter on the IO::Socket::INET->new call sets the queue size, not the timeout).

Simply place the following line:

$server->timeout(30);

before your accept() call. Then you'll time out after 30 seconds. Or you could set it at 10 seconds and requeue the accept() if that's what you want to do.
Craig A Berry
Honored Contributor

Re: Perl alarms don't work on VMS

I didn't explain very well that the reason for shortening the timeout to, say, 10 seconds, is that you would then not need the alarm at all. It looks a lot like the alarm is an attempt to set a timeout the hard way and is not really necessary.

And for completeness I should mention that you can avoid signal deferral by using POSIX::sig_action instead of %SIG, but then you expose your self to the potential problems that deferred signals were designed to avoid.