http://qs1969.pair.com?node_id=552515

SirBones has asked for the wisdom of the Perl Monks concerning the following question:

Hey folks. I asked a question in the CB the other day, and thought via bart's help I had it solved. But as I play more I've run into more questions. Have looked around a bit (i.e., in 436492 and some of its links, and elsewhere) but really haven't found an explanation. I certainly apologize in advance if this has been answered in some obvious place.

To start with the obvious. On win32:

#!/usr/bin/perl use strict; use warnings; while (1) { print "still here...\n"; sleep 30; }

Pressing ctrl-C results in a (virtually) instantaneous:

Terminating on signal SIGINT(2)

Fine. Now this:

#!/usr/bin/perl use strict; use warnings; $SIG{INT} = \&handleit; while (1) { print "still here...\n"; sleep 30; } sub handleit { die "I caught it."; }

If I run this on my win32 system, and issue a ctrl-C, the handler does not display its expected response until after the sleep has finished (about 30 seconds later). On Linux, the sleep is broken immediately and the handler runs right away (as I would expect).

I'm confused. It seems that the first example shows that indeed a ctrl-C under win32 is (as expected) breaking into the sleep properly. If this is the case, where the heck has the program control gone in the second example? Where exactly are things between the time of the ctrl-C and when the sleep ends and the handler runs?

I'm on Windows XP Pro, SP 1. My Perl v5.8.7, ActiveState binary build 815.

Cheers,
Ken

Correction: Moved up my system info, and clarified sleep behavior.

"This bounty hunter is my kind of scum: Fearless and inventive." --J.T. Hutt

Replies are listed 'Best First'.
Re: win32, ctrl-c, sleep, and signals
by BrowserUk (Patriarch) on May 30, 2006 at 15:41 UTC

    This is caused by the 'safe signals' that were introduced by 5.8.0. The sleep is treated a single opcode and so the signal is not seen until after the opcode completes. See the 'safe signals' section of perl58delta. Also see perl581delta for how to bypass this and get the old unsafe behaviour back.

    c:\test>set PERL_SIGNALS=unsafe c:\test>p1 [0] Perl> $SIG{ INT } = sub{ print 'Caught signal INT'; };; [0] Perl> print 'still here' while sleep 10;; still here Caught signal INT still here Terminating on signal SIGBREAK(21)

    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
      This is caused by the 'safe signals' that were introduced by 5.8.0.

      Fair enough, but that doesn't seem to explain why I get different behavior on Linux (immediate exit), where I'm running Perl 5.8.0.

      Thanks,
      Ken

      "This bounty hunter is my kind of scum: Fearless and inventive." --J.T. Hutt

        You have to remember that Win32 does not have signals as a native concept. Perl's support for them is simulated and limited, and is actually implemented via the process message queue. This is the code that implements the signal emulations from win32.c:

        Setting the environment variable PERL_SIGNALS=unsafe allows ^C to interupt sleep. Without it, the signal handler doesn't get invoked until the sleep is over.


        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.
      Are you sure? It works fine for me on Unix with perl 5.8.3. It seems to me that sleep would qualify as a "potentially blocking operation" mentioned in perl58delta...
        Are you sure?

        Yes. See Re^3: win32, ctrl-c, sleep, and signals.


        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.
Re: win32, ctrl-c, sleep, and signals
by cdarke (Prior) on May 30, 2006 at 17:11 UTC
    See ActiveState's ActivePerl FAQ - Implementation Quirks documentation, "Why doesn't signal handling work on Windows?". Signals are a UNIX thing, and are only implemented in the C runtime library on Windows enough to conform to C89 standards. For example, on Linux sleep will raise a SIGALRM when it times out, but on Windows SIGALRM is not supported (alarm is one of the functions listed as not implemented by ActiveState).
    Windows uses a different architecture for console handling compared to UNIX terminal handling. In Win32 a CTRL+C (or Break) is controlled using SetConsoleCtrlHandler, not signals in the UNIX sense (even though the MSDN talks about raising a signal).
      alarm() is implemented in perl5.8+ on win32. just try it:
      perl -e "eval {local $SIG{ALRM} = sub { die qq!alarm\n! };alarm 1;slee +p 2;alarm 0;};die $@ || 'nothing'"
Re: win32, ctrl-c, sleep, and signals
by sgifford (Prior) on May 30, 2006 at 15:38 UTC
    I seem to recall that that on Windows, I seem to need to set a handler for $SIG{BREAK} to catch a CTRL-C. I usually set the handlers for $SIG{BREAK}, $SIG{INT}, $SIG{TERM}, and $SIG{HUP} to the same handler.
Re: win32, ctrl-c, sleep, and signals
by jesuashok (Curate) on May 30, 2006 at 15:32 UTC
    Hi

    #!/usr/bin/perl use strict; use warnings; $SIG{INT} = 'handleit'; while (1) { print "still here...\n"; sleep 30; } sub handleit { print "I caught it."; exit(1); }
    I tried the above code in windows it works for me.

    "Keep pouring your ideas"
      I've tried it on w2k and I get the same issue. If I control C before the first print it exits without the die message.
      Weird.
        Hi

        The reason could be die raises a signal. so Inside a signal handler, If a signal getting raised it will lead to misleading result. that is what happened in your code.

        Remove the die and use exit there. I have updated my node accordingly. use the same code and try in your important.

        That will work.

        "Keep pouring your ideas"