1Further topics in interrupt/signal handling 2=========================================== 3 4Testing interrupts 5------------------ 6 7When writing documentation, one sometimes wants to check that certain 8code can be interrupted in a clean way. The best way to do this is to 9use :func:`cysignals.alarm`. 10 11The following is an example of a doctest demonstrating that the 12SageMath function :func:`factor()` can be interrupted: 13 14.. code-block:: pycon 15 16 >>> from cysignals.alarm import alarm, AlarmInterrupt 17 >>> try: 18 ... alarm(0.5) 19 ... factor(10**1000 + 3) 20 ... except AlarmInterrupt: 21 ... print("alarm!") 22 alarm! 23 24If you use the SageMath doctesting framework, you can instead doctest 25the exception in the usual way (the Python ``doctest`` module exits 26whenever a ``KeyboardInterrupt`` is raised in a doctest). 27To avoid race conditions, make sure that the calls to ``alarm()`` and 28the function you want to test are in the same doctest: 29 30.. code-block:: pycon 31 32 >>> alarm(0.5); factor(10**1000 + 3) 33 Traceback (most recent call last): 34 ... 35 AlarmInterrupt 36 37.. _advanced-sig: 38 39Signal handling without exceptions 40---------------------------------- 41 42There are several more specialized functions for dealing with interrupts. As 43mentioned above, ``sig_on()`` makes no attempt to clean anything up (restore 44state or freeing memory) when an interrupt occurs. In fact, it would be 45impossible for ``sig_on()`` to do that. If you want to add some cleanup code, 46use ``sig_on_no_except()`` for this. This function behaves *exactly* like 47``sig_on()``, except that any exception raised (like ``KeyboardInterrupt`` or 48``RuntimeError``) is not yet passed to Python. Essentially, the exception is 49there, but we prevent Cython from looking for the exception. Then 50``cython_check_exception()`` can be used to make Cython look for the exception. 51 52Normally, ``sig_on_no_except()`` returns 1. If a signal was caught and an 53exception raised, ``sig_on_no_except()`` instead returns 0. The following 54example shows how to use ``sig_on_no_except()``:: 55 56 def no_except_example(): 57 if not sig_on_no_except(): 58 # (clean up messed up internal state) 59 60 # Make Cython realize that there is an exception. 61 # It will look like the exception was actually raised 62 # by cython_check_exception(). 63 cython_check_exception() 64 # (some long computation, messing up internal state of objects) 65 sig_off() 66 67There is also a function ``sig_str_no_except(s)`` which is analogous to 68``sig_str(s)``. 69 70.. NOTE:: 71 72 See the file `src/cysignals/tests.pyx <https://github.com/sagemath/cysignals/blob/master/src/cysignals/tests.pyx>`_ 73 for more examples of how to use the various ``sig_*()`` functions. 74 75Releasing the Global Interpreter Lock (GIL) 76------------------------------------------- 77 78All the functions related to interrupt and signal handling do not require the 79`Python GIL 80<http://docs.cython.org/src/userguide/external_C_code.html#acquiring-and-releasing-the-gil>`_ 81(if you don't know what this means, you can safely ignore this section), they 82are declared ``nogil``. This means that they can be used in Cython code inside 83``with nogil`` blocks. If ``sig_on()`` needs to raise an exception, the GIL is 84temporarily acquired internally. 85 86If you use C libraries without the GIL and you want to raise an exception before 87calling :ref:`sig_error() <sig-error>`, remember to acquire the GIL while 88raising the exception. Within Cython, you can use a `with gil context 89<http://docs.cython.org/src/userguide/external_C_code.html#acquiring-the-gil>`_. 90 91.. WARNING:: 92 93 The GIL should never be released or acquired inside a ``sig_on()`` block. If 94 you want to use a ``with nogil`` block, put both ``sig_on()`` and 95 ``sig_off()`` inside that block. When in doubt, choose to use 96 ``sig_check()`` instead, which is always safe to use. 97 98