in reply to Alarms with ActivePerl do not work properly

The problem is that the signal emulation won't interrupt a blocking read. That's because the read runs in the kernel space, but the emulation runs in user space. It's a bug in the emulation, but not one that is easily corrected.

The following small mod makes it work well enough for most purposes:

#! /usr/bin/perl -w use strict; # Starting a co-process to read from. my $procid = open(READ, '-|', 'perl -e "$|=1; for ($i=0;$i<10;$i++) {print \"Line $i\n\"; sleep +1;}"' ); my $timeout = 0; $SIG{ALRM} = sub { $timeout = 1; }; alarm(3); # Reading from co-process. while (!$timeout) { my $line = <READ>; last unless defined $line; print $line; sleep 1; } kill('INT', $procid) if $timeout;

Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.
  • Comment on Re: Alarms with ActivePerl do not work properly (small modification)
  • Download Code

Replies are listed 'Best First'.
Re^2: Alarms with ActivePerl do not work properly (small modification)
by tilly (Archbishop) on Jan 13, 2011 at 00:55 UTC
    The downside to your modification is that if lines come 3 per second, you still only read one per second. And if lines come one every 2 seconds, your alarm has even odds of not doing anything.

    I also think that the emulation can be fixed. Just use a select/sysread loop, which gives you lots of opportunities to be interrupted. Yes, it is a busy wait. But if you only do it when there is an outstanding alarm, I think it is a reasonable tradeoff.

    In fact it is even possible to make that fix in pure Perl. All you have to do is tie the filehandle to an implementation that has a READLINE that does the select/sysread loop and returns when it completes a line of text. (Don't forget to strip out "\r".)

      The downside to your modification is that if lines come 3 per second, you still only read one per second. And if lines come one every 2 seconds, your alarm has even odds of not doing anything.

      The sleep can be varied to suit. It would be better to invoke the sleep before the read.

      In essence, the trick is to ensure that the read doesn't block. I've posted several other variations on the theme here over the years. Some more thorough than others.

      I also think that the emulation can be fixed. Just use a select/sysread loop, ...

      select doesn't work on filehandles on Win32.

      In fact it is even possible to make that fix in pure Perl.

      I guess that "fact" is tempered by the above.

        Windows is really that broken?

        I'm glad I don't use Windows then.

Re^2: Alarms with ActivePerl do not work properly (small modification)
by ikegami (Patriarch) on Jan 13, 2011 at 17:17 UTC

    The problem is that the signal emulation won't interrupt a blocking read.

    Did I test it wrong, cause it wasn't triggering for me after the read returned either.

      Did I test it wrong,

      No, your test is correct, though the interpretation may be a little off.

      In this case, it isn't that the IO is causing the signal to be deferred. The alarm 'signal' is being simulated by a one-shot timer, which as the name applies happens once. If the code is not in an interuptable state when it does, the timer is effectively discarded.

      That could be fixed by using an Overlapped-IO Read and entering an interuptable wait and cancelling the pending IO if the timer goes off.

      Indeed, ubiquitous use of Overlapped IO would allow the whole select/signals emulation to be done in a far more POSIX-compliant fashion, but that would be a major re-write of the perl/win32 subsystems and I can't see anyone taking that task on.


      Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
      "Science is about questioning the status quo. Questioning authority".
      In the absence of evidence, opinion is indistinguishable from prejudice.