Cython, Python and KeyboardInterrupt ignored
Question: Is there a way to interrupt (`Ctrl+C`) a Python script based on a loop that is
embedded in a Cython extension?

I have the following python script:

    
    
    def main():
    
        # Intantiate simulator
        sim = PySimulator()
        sim.Run()
    
    if __name__ == "__main__":
        # Try to deal with Ctrl+C to abort the running simulation in terminal
        # (Doesn't work...)
        try:
            sys.exit(main())
        except (KeyboardInterrupt, SystemExit):
            print '\n! Received keyboard interrupt, quitting threads.\n'
    

This runs a loop that is part of a C++ Cython extension. Then, while pressing
`Ctrl+C`, the `KeyboardInterrupt` is thrown but ignored, and the program keeps
going until the end of the simulation.

The work around I found, is to handle the exception from within the extension
by catching the `SIGINT` signal :

    
    
    #include <execinfo.h>
    #include <signal.h>
    
    static void handler(int sig)
    {
      // Catch exceptions
      switch(sig)
      {
        case SIGABRT:
          fputs("Caught SIGABRT: usually caused by an abort() or assert()\n", stderr);
          break;
        case SIGFPE:
          fputs("Caught SIGFPE: arithmetic exception, such as divide by zero\n",
                stderr);
          break;
        case SIGILL:
          fputs("Caught SIGILL: illegal instruction\n", stderr);
          break;
        case SIGINT:
          fputs("Caught SIGINT: interactive attention signal, probably a ctrl+c\n",
                stderr);
          break;
        case SIGSEGV:
          fputs("Caught SIGSEGV: segfault\n", stderr);
          break;
        case SIGTERM:
        default:
          fputs("Caught SIGTERM: a termination request was sent to the program\n",
                stderr);
          break;
      }
      exit(sig);
    
    }
    

Then :

    
    
    signal(SIGABRT, handler);
    signal(SIGFPE,  handler);
    signal(SIGILL,  handler);
    signal(SIGINT,  handler);
    signal(SIGSEGV, handler);
    signal(SIGTERM, handler);
    

Can't I make this work from Python, or at least from Cython instead ? As I am
about to port my extension under Windows/MinGW, I would appreciate to have
something less Linux specific.


Answer: You have to periodically check for pending signals, for example, on every Nth
iteration of the simulation loop:

    
    
    from cpython.exc cimport PyErr_CheckSignals
    
    cdef Run(self):
        while True:
            # do some work
            PyErr_CheckSignals()
    

`PyErr_CheckSignals` will run signal handlers installed with
[signal](http://docs.python.org/2/library/signal.html) module (this includes
raising `KeyboardInterrupt` if necessary).

`PyErr_CheckSignals` is pretty fast, it's OK to call it often. Note that it
should be called from the main thread, because Python runs signal handlers in
the main thread. Calling it from worker threads has no effect.

**Explanation**

Since signals are delivered asynchronously at unpredictable times, it is
problematic to run any meaningful code directly from the signal handler.
Therefore, Python queues incoming signals. The queue is processed later as
part of the interpreter loop.

If your code is fully compiled, interpreter loop is never executed and Python
has no chance to check and run queued signal handlers.

