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

I was working on a quick hack of a script which included a nasty loop that will run for at least an hour. Sometimes I'm an impatient programmer, and don't like having my CPU block for an extended period of time, so I wanted to stop the loop, go in and edit the hack to restart the loop where it left off, and then re-start it later.... so I threw in this code:
BEGIN{ $SIG{INT}=sub{ print $counter, $/ } }
But I'm running this hack on a Win32 box, so ctrl-c failed to trigger my sigtrap. I eventually gave up trying to do it smart and instead just have the thing printing $counter out to STDOUT. It works, but I kind of wish I could have done it right. Does anyone know how to do a good trap like that on a Win32 machine?

Replies are listed 'Best First'.
Re: Win32 Interrupts
by tye (Sage) on Sep 20, 2000 at 08:12 UTC

    Well, I did find a way to make it work under Win32 (tested under Win98 and WinNT). This seems to indicate several bugs in Perl 5.6.0 for Win32. But first, the code that works:

    # The following hack allows $SIG{INT} to work under Win32: my $child= fork(); if( defined $child && 0 == $child ) { # Child: exit( 0 ); } # Parent: my $go= 1; $SIG{INT}= sub { $go= 0; warn "Got INT\n" }; my $i= 0; while( $go && $i < 10_000_000 ) { $i++; } print "Done: $i\n";

    Now, I recall reading that $$ is supposed to be negative for the threads that are created by Win32 Perl's pseudo-fork(). But in coming up with the above code I found that $$ is negative in the parent and positive in the child. kill and waitpid seem to return immediately after doing nothing. The parent exit()ing sometimes kills the "child" thread and sometimes lets it run. I even had a case where CTRL-C caused the parent to start over (and no, I quadruple-checked that it wasn't the child acting like the parent).

    And 2 of 4 times using this code and hitting CTRL-C caused Perl to panic under WinNT (no panics after dozens of runs under Win98 -- Win98 doesn't care nearly as much if your code goes romping mearilly through random chunks of RAM).

    Anyone been keeping up with p5p and know how much of this is already know to the developers. I would think most of this is since it so easy to find and they'd be intersted in testing the new pseudo-fork(). tilly? :)

            - tye (but my friends call me "Tye")
      I keep up enough to have random tidbits, but I don't follow closely. Sorry. I think this should definitely be reported as a bug though. Ben
(Ovid) Re: Win32 Interrupts
by Ovid (Cardinal) on Sep 20, 2000 at 06:00 UTC
    Bummer. It appears to be a portability issue here (as far as I can tell). I'm using examples straight out of the Cookbook and they don't work. I even tried setting $SIG{INT} = 'IGNORE';, but to no avail.

    However, I searched the perlbug database and couldn't find a problem like this. In fact, I verifed that others are successfully using %SIG, so I assume that I must be misunderstand something. So let me see if I understand this. The following should generate an infinite loop which should do nothing but fill the screen with numbers and cannot be broken out of with CTRL-C:

    #!/usr/bin/perl -w use strict; $SIG{INT} = 'IGNORE'; my $count=0; while (){ print $count++; }
    Unfortunately, when I hit CTRL-C, the program stops on a dime.

    Cheers,
    Ovid

    Join the Perlmonks Setiathome Group or just go the the link and check out our stats.

(jcwren) RE: Win32 Interrupts
by jcwren (Prior) on Sep 20, 2000 at 06:41 UTC
    The crudest way would be to check for the existence of a file periodically, and either pause or checkpoint the system when you see it.

    Another slightly more refined way is to use a non-blocking socket, and check for data being present on the socket. Use another app to connect to the socket, and send control information. You don't need select() for this to work.

    Probably the best way would be to use Win32::API, and hook some code that would poll the keyboard of the active process.

    I suspect that the problem is dependant on the nature of the loop, the Perl compiler is not getting around to checking for I/O in certain types of loops. Under DOS, and to some extent Windows, keyboard I/O has to be checked for to receive a break signal. This is unlink Unix OS's, which send a signal to the process (DOS and Windows apps don't really have that concept, unless it's written into them).

    --Chris

    e-mail jcwren
Re: Win32 Interrupts
by extremely (Priest) on Sep 20, 2000 at 05:38 UTC

    We offered a number of failed suggestions to this on the CB. =) Win9x makes things a bit harder. The select trick won't work well to capture keyboard input and the MS way is supposedly rather nasty for quick hacks.

    I'd like to make a simple sniff for input loop to solve his question but can't do so. Is there an easier way on Win9x boxes to do keyboard capture that is non-blocking that I don't know of?

    What I finally recommend is this, which I sometimes use for scripts that restart themselves with cron if they die:

    open LINETO, ">./lineto.txt"; $oldfh = select(LINETO); $| = 1; select($oldfh); for ($1 etc. etc.) { #do you stuff here ##done with stage $i? seek LINETO,0,0; print LINETO "$i\n"; #post cleanup. } print LINETO, "Finito\n"; close LINETO;

    But I have no idea what kind of slowdown that would add, esp. since it would depend on OS and FileSystem load.

    --
    $you = new YOU;
    honk() if $you->love(perl)