Beefy Boxes and Bandwidth Generously Provided by pair Networks
The stupid question is the question not asked
 
PerlMonks  

Force 2 'ctrl-c's to kill program

by albob (Sexton)
on Feb 11, 2013 at 17:11 UTC ( #1018190=perlquestion: print w/replies, xml ) Need Help??
albob has asked for the wisdom of the Perl Monks concerning the following question:

Hi
I would like to force a user to have to hit ctrl-c twice within 2 seconds in order to kill my program (safety net to prevent unintentional killing of the program). Ideally my code would look like the following:
my $prev_ctrlc = 0; $SIG{'INT'} = \&control_c_observed; sub control_c_observed { if ($prev_ctrlc ==0) { print "Second ctrl-c within 2 seconds required\n"; $prev_ctrlc = 1; sleep (2); $prev_ctrlc = 0; } else { print "This was the 2nd!Dying.\n"; exit; } }

However this obviously does not work (or I would not be hee :)). It looks like the first entry to "control_c_observed" must fully complete before the 2nd interupt request will be serviced.
Does anyone know of a way of achieving my desired behavior?
Thanks
Alan

Replies are listed 'Best First'.
Re: Force 2 'ctrl-c's to kill program
by BrowserUk (Pope) on Feb 11, 2013 at 17:22 UTC

    Try this:

    #! perl -slw use strict; use 5.010; use Time::HiRes qw[ time sleep ]; $|++; $SIG{ INT } = sub { state $last = 0; if( ( time - $last ) > 2 ) { $last = time; return; } die 'Interupted by ^C^C'; }; while( 1 ) { printf "\rtum te tum: %f", time; sleep 0.1; }

    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    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.
      This certainly seems to work. Must get my head around what it is doing now. Thanks.
        Must get my head around what it is doing now.

        $SIG{ INT } = sub { ## State makes $last a closure; that is a variable that remember' +s its value ## between invocations of the subroutine state $last = 0; ## if the time now is greater than 2 seconds later than the last +time we saw a ^C if( ( time - $last ) > 2 ) { ## Overwrite the last time with the current time $last = time; ## And just return; ignoring this ^C return; } ## However, if it is less than 2 seconds; die. die 'Interupted by ^C^C'; };

        With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
        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.
Re: Force 2 'ctrl-c's to kill program
by jethro (Monsignor) on Feb 11, 2013 at 17:18 UTC

    Haven't tested this, but why not use time() to record the time of the first ctrl-c and break only if the next ctrl-c has time()-$previoustime<=2

      Cheers. I tried someting like that but again it appears that while I am inside my 1st control_c_observed subroutine, the 2nd Ctrl-C only gets serviced after the routine has finished. That is, it does not appear to allow the 2nd ctrl-c affect the sub-routine called by the 1st Ctrl-C. Now, it could be that I implemented it incorrectly!

        So you didn't eliminate the sleep() call? Think about it, why would you still need the sleep call when you know the time the first ctrl-c happened. Without the sleep call the ctrl-c subroutine should be finished almost immediately.

        PS: Using something like sleep() in an interrupt routine is bad design. Interrupt routines should never have a long running time because the code they are interrupting might have expectations of things occuring at a certain speed without seconds-long freezing. For example the user interface

Re: Force 2 'ctrl-c's to kill program
by ww (Archbishop) on Feb 11, 2013 at 17:44 UTC
    TIMTOWTDI

    Alternate approach; closer to OP's original (and a surprise to me that it appears to work!)

    #!/usr/bin/perl use 5.016; use warnings; use strict; my $prev_ctrlc = 0; if( ($prev_ctrlc == 0) || ($prev_ctrlc == 1) ) { $SIG{'INT'} = \&control_c_observed; sleep 1; for (1..1e3) { say "\t nothing yet"; sleep 2; } } sub control_c_observed { if ($prev_ctrlc == 0) { print "Second ctrl-c within 2 seconds required\n"; $prev_ctrlc = 1; } else { $prev_ctrlc++; } if ($prev_ctrlc == 2 ) { say "OK, that's two of 'em!"; exit; } }

    Sample run:

    C:\>C:\SQLite\1018190.pl nothing yet nothing yet nothing yet # single tap here Second ctrl-c within 2 seconds required nothing yet nothing yet # double tap here OK, that's two of 'em! C:\>

    The sleep's could annoy your users, as they might seem like the machine is (briefly) locking up.


    If you didn't program your executable by toggling in binary, it wasn't really programming!

      Agreed on sleep. I need to stop using it and start remembering time instead. Cheers

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://1018190]
Front-paged by Arunbear
help
Chatterbox?
[Corion]: Meh. My bank removed (part of) their CSV download facilities. Now I will either have to implement a full scraper or automate the download using the HBCI interface instead (or just get a new account elsewhere...)
[Corion]: On the upside, I spend a lot of time thinking this weekend about how to actually implement rate limiting for futures, and if things work out, maybe even loading a configuration from an external file makes sense
[Corion]: I've also found some interesting invariants that I have to think/write about more. A simple rate limiter will never change the order of the input, while a limiter that allows for parallel execution will change the order. But my API currently allows for bo
[Corion]: ... for both, and I'm not sure if I want to add the cruft from the parallel API (a token that you need to hold on to while you hold the lock) to the rate limiting API too, to allow seamless up/downgrades, or not.
[Corion]: Also, rate limiting will look great with await: my $token = await $limiter-> limit($hostname); instead of my $f = $limiter->limit( $hostname )->then(sub { my( $token)=@_; ... });

How do I use this? | Other CB clients
Other Users?
Others drinking their drinks and smoking their pipes about the Monastery: (9)
As of 2017-10-23 08:21 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    My fridge is mostly full of:

















    Results (277 votes). Check out past polls.

    Notices?