[Python-modules-commits] [cysignals] 02/04: Import cysignals_1.6.4+ds.orig.tar.xz
Jerome Benoit
calculus-guest at moszumanska.debian.org
Sat Jun 10 08:02:56 UTC 2017
This is an automated email from the git hooks/post-receive script.
calculus-guest pushed a commit to branch master
in repository cysignals.
commit 868690ba5b4c2a8078b07d7f712466cd4f97f20a
Author: Jerome Benoit <calculus at rezozer.net>
Date: Fri Jun 9 18:34:39 2017 +0400
Import cysignals_1.6.4+ds.orig.tar.xz
---
MANIFEST.in | 8 +
Makefile | 125 ++++++++++--
PKG-INFO | 2 +-
VERSION | 2 +-
docs/source/conf.py | 12 ++
docs/source/index.rst | 444 +++--------------------------------------
docs/source/interrupt.rst | 249 +++++++++++++++++++++++
docs/source/pselect.rst | 3 +
docs/source/pysignals.rst | 2 +
docs/source/sigadvanced.rst | 96 +++++++++
docs/source/sigerror.rst | 43 ++++
docs/source/signals.rst | 59 ++++++
example/cysignals_example.pyx | 6 +-
example/setup.py | 3 +-
rundoctests.py | 30 ++-
setup.cfg | 5 +
setup.py | 147 +++++++++-----
src/cysignals/implementation.c | 2 +-
src/cysignals/macros.h | 65 ++++--
src/cysignals/memory.pxd | 4 -
src/cysignals/memory.pxi | 3 +-
src/cysignals/pselect.pyx | 81 +++++++-
src/cysignals/pxi.h | 12 --
src/cysignals/pxi_warning.h | 1 +
src/cysignals/pysignals.pxd | 4 +
src/cysignals/pysignals.pyx | 350 ++++++++++++++++++++++++++++++++
src/cysignals/signals.pxd | 85 +++++---
src/cysignals/signals.pxi | 23 +--
src/cysignals/signals.pyx | 53 +++--
src/cysignals/tests.pyx | 60 +++++-
src/cysignals/tests_helper.c | 2 -
src/scripts/cysignals-CSI | 65 ++++--
32 files changed, 1384 insertions(+), 662 deletions(-)
diff --git a/MANIFEST.in b/MANIFEST.in
new file mode 100644
index 0000000..84eff69
--- /dev/null
+++ b/MANIFEST.in
@@ -0,0 +1,8 @@
+global-include README README.rst VERSION LICENSE
+global-include Makefile configure configure.ac
+global-include setup.py rundoctests.py *.pyx
+graft src
+graft docs/source
+prune build
+prune dist
+prune tmp
diff --git a/Makefile b/Makefile
index 7a8c251..f1c908e 100644
--- a/Makefile
+++ b/Makefile
@@ -1,49 +1,139 @@
# Optional Makefile for easier development
-PYTHON=python
+VERSION = $(shell cat VERSION)
+
+PYTHON = python
+PIP = $(PYTHON) -m pip -v
+DOCTEST = $(PYTHON) -B rundoctests.py
+LS_R = ls -Ra1
+
+
+#####################
+# Build
+#####################
all: build doc
build: configure
$(PYTHON) setup.py build
-install: build
- $(PYTHON) setup.py install
+install: configure
+ $(PIP) install --no-index --ignore-installed .
dist: configure
chmod go+rX-w -R .
umask 0022 && $(PYTHON) setup.py sdist --formats=bztar
-distcheck: dist
- mkdir -p dist/check
- VERSION=`cat VERSION`; cd dist/check && tar xjf ../cysignals-$$VERSION.tar.bz2
- VERSION=`cat VERSION`; cd dist/check/cysignals-$$VERSION && ./configure && $(MAKE) all check
- rm -rf dist/check
-
doc:
cd docs && $(MAKE) html
+
+#####################
+# Clean
+#####################
+
clean: clean-doc clean-build
+ rm -rf tmp
clean-build:
- rm -rf build example/build example/*.c
+ rm -rf build example/build example/*.cpp
clean-doc:
- cd docs && $(MAKE) clean
+ rm -rf docs/build
distclean: clean
rm -rf autom4te.cache
rm -f config.log config.status
-check: check-doctest check-example
+
+#####################
+# Check
+#####################
+
+test: check
+
+check: check-tmp
+
+check-all: check-tmp
+ $(MAKE) check-install
+
+# Install and check
+check-install: check-doctest check-example
check-doctest: install
- $(PYTHON) -B rundoctests.py src/cysignals/*.pyx
+ $(DOCTEST) src/cysignals/*.pyx
check-example: install
- cd example && $(PYTHON) setup.py build
+ cd example && $(PYTHON) setup.py clean build
-test: check
+check-gdb: install
+ $(PYTHON) testgdb.py
+
+
+#####################
+# Check installation
+#####################
+#
+# Test 2 installation scenarios without a real installation
+# - prefix (with --prefix and --root)
+# - user (with --user)
+
+check-tmp:
+ $(MAKE) check-prefix
+ $(MAKE) check-user
+
+prefix-install: configure
+ rm -rf tmp/local tmp/build
+ $(PYTHON) setup.py install --prefix="`pwd`/tmp/local" --root=tmp/build
+ cd tmp && mv "build/`pwd`/local" local
+ cd tmp && ln -s local/lib*/python*/site-packages site-packages
+
+check-prefix: check-prefix-doctest check-prefix-example
+
+check-prefix-doctest: prefix-install
+ export PYTHONPATH="`pwd`/tmp/site-packages" && $(DOCTEST) src/cysignals/*.pyx
+
+check-prefix-example: prefix-install
+ rm -rf example/build
+ export PYTHONPATH="`pwd`/tmp/site-packages" && cd example && $(PYTHON) setup.py clean build
+
+check-user: check-user-doctest check-user-example
+
+user-install: configure
+ rm -rf tmp/user
+ export PYTHONUSERBASE="`pwd`/tmp/user" && $(PYTHON) setup.py install --user --single-version-externally-managed --record=/dev/null
+
+check-user-doctest: user-install
+ export PYTHONUSERBASE="`pwd`/tmp/user" && $(DOCTEST) src/cysignals/*.pyx
+
+check-user-example: user-install
+ export PYTHONUSERBASE="`pwd`/tmp/user" && cd example && $(PYTHON) setup.py clean build
+
+distcheck: dist
+ rm -rf dist/check
+ mkdir -p dist/check
+ cd dist/check && tar xjf ../cysignals-$(VERSION).tar.bz2
+ cd dist/check/cysignals-$(VERSION) && $(LS_R) >../dist0.ls
+ cd dist/check/cysignals-$(VERSION) && $(MAKE) all
+ cd dist/check/cysignals-$(VERSION) && $(MAKE) distclean
+ cd dist/check/cysignals-$(VERSION) && $(LS_R) >../dist1.ls
+ cd dist/check; diff -u dist0.ls dist1.ls || { echo >&2 "Error: distclean after all leaves garbage"; exit 1; }
+ cd dist/check/cysignals-$(VERSION) && $(MAKE) check-user
+ cd dist/check/cysignals-$(VERSION) && ./configure --enable-debug
+ cd dist/check/cysignals-$(VERSION) && $(MAKE) check-prefix
+ cd dist/check/cysignals-$(VERSION) && $(MAKE) distclean
+ cd dist/check/cysignals-$(VERSION) && $(LS_R) >../dist2.ls
+ cd dist/check; diff -u dist0.ls dist2.ls || { echo >&2 "Error: distclean after check-tmp leaves garbage"; exit 1; }
+ cd dist/check/cysignals-$(VERSION) && $(MAKE) dist
+ cd dist/check/cysignals-$(VERSION) && tar xjf dist/cysignals-$(VERSION).tar.bz2
+ cd dist/check/cysignals-$(VERSION)/cysignals-$(VERSION) && $(LS_R) >../../dist3.ls
+ cd dist/check; diff -u dist0.ls dist3.ls || { echo >&2 "Error: sdist is not reproducible"; exit 1; }
+ rm -rf dist/check
+
+
+#####################
+# Maintain
+#####################
configure: configure.ac
autoconf
@@ -51,4 +141,7 @@ configure: configure.ac
@rm -f src/config.h.in~
.PHONY: all build doc install dist doc clean clean-build clean-doc \
- distclean check check-doctest check-example test
+ distclean test check check-all check-tmp check-install \
+ check-doctest check-example \
+ check-prefix prefix-install check-prefix-doctest check-prefix-example \
+ check-user user-install check-user-doctest check-user-example
diff --git a/PKG-INFO b/PKG-INFO
index 7832f32..eb3e749 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,6 +1,6 @@
Metadata-Version: 1.0
Name: cysignals
-Version: 1.3.2
+Version: 1.6.4
Summary: Interrupt and signal handling for Cython
Home-page: https://github.com/sagemath/cysignals
Author: Martin R. Albrecht, François Bissey, Volker Braun, Jeroen Demeyer
diff --git a/VERSION b/VERSION
index 1892b92..9edc58b 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.3.2
+1.6.4
diff --git a/docs/source/conf.py b/docs/source/conf.py
index b2bf184..ad8eaae 100644
--- a/docs/source/conf.py
+++ b/docs/source/conf.py
@@ -29,6 +29,7 @@ import os
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
+ 'sphinx.ext.autodoc',
'sphinx.ext.intersphinx',
]
@@ -265,3 +266,14 @@ texinfo_documents = [
# Intersphinx reference to Python
intersphinx_mapping = {'python': ('https://docs.python.org/2.7', None)}
+
+
+# Monkey-patch inspect with Cython support
+import inspect
+def isfunction(obj):
+ for cls in inspect.getmro(type(obj)):
+ if "__code__" in cls.__dict__:
+ return True
+ return False
+
+inspect.isfunction = isfunction
diff --git a/docs/source/index.rst b/docs/source/index.rst
index 4577d61..436d21a 100644
--- a/docs/source/index.rst
+++ b/docs/source/index.rst
@@ -14,432 +14,40 @@ While this is running, pressing ``CTRL-C`` has no effect. The only way
out is to kill the Python process. On certain systems, you can still
quit Python by typing ``CTRL-\`` (sending a Quit signal) instead of
``CTRL-C``.
+The package cysignals provides functionality to deal with this,
+see :ref:`section_interrupt`.
-This module provides two related mechanisms to deal with interrupts:
+Besides this, cysignals also provides Python functions/classes
+to deal with signals.
+These are not directly related to interrupts in Cython,
+but provide some supporting functionality beyond what Python provides,
+see :ref:`index_python`.
-* :ref:`Use sig_check() <section_sig_check>` if you are writing mixed
- Cython/Python code. Typically this is code with (nested) loops where every
- individual statement takes little time.
+Interrupt/Signal Handling
+-------------------------
-* :ref:`Use sig_on() and sig_off() <section_sig_on>` if you are calling external
- C libraries or inside pure Cython code (without any Python functions) where
- even an individual statement, like a library call, can take a long time.
+Dealing with interrupts and other signals using ``sig_check`` and ``sig_on``:
-The functions ``sig_check()``, ``sig_on()`` and ``sig_off()`` can be put in all
-kinds of Cython functions: ``def``, ``cdef`` or ``cpdef``. You cannot put them
-in pure Python code (files with extension ``.py``).
+.. toctree::
+ interrupt
+ signals
+ sigadvanced
-Basic example
--------------
+Error handling
+--------------
-The ``sig_check()`` in the loop below ensures that the loop can be
-interrupted by ``CTRL-C``::
+Defining error callbacks for external libraries using ``sig_error``:
- include "cysignals/signals.pxi"
+.. toctree::
+ sigerror
- from libc.math cimport sin
+.. _index_python:
- def sine_sum(double x, long count):
- cdef double s = 0
- for i in range(count):
- sig_check()
- s += sin(i*x)
- return s
+Signal-related interfaces for Python code
+-----------------------------------------
-The line ``include "cysignals/signals.pxi"`` must be put in every
-``.pyx`` file using cysignals.
-You must not put this in a ``.pxd`` file; a ``.pxi`` file included only
-in ``.pyx`` files also works.
+cysignals provides further support for system calls related to signals:
-Because of `cython/cython#483 <https://github.com/cython/cython/pull/483>`_,
-you should add ``include_path=sys.path`` to your ``cythonize()`` call in
-``setup.py`` (otherwise Cython will not find :file:`cysignals/signals.pxi`).
-See the `example <https://github.com/sagemath/cysignals/tree/master/example>`_
-directory for this complete working example.
-
-.. NOTE::
-
- Cython ``cdef`` or ``cpdef`` functions with a return type (like ``cdef int
- myfunc():``) need to have an `except value
- <http://docs.cython.org/src/userguide/language_basics.html#error-return-values>`_
- to propagate exceptions. Remember this whenever you write ``sig_check()`` or
- ``sig_on()`` inside such a function, otherwise you will see a message like
- ``Exception KeyboardInterrupt: KeyboardInterrupt() in <function name>
- ignored``.
-
-.. _section_sig_check:
-
-Using ``sig_check()``
----------------------
-
-``sig_check()`` can be used to check for pending interrupts. If an interrupt
-happens during the execution of C or Cython code, it will be caught by the next
-``sig_check()``, the next ``sig_on()`` or possibly the next Python statement.
-With the latter we mean that certain Python statements also check for
-interrupts, an example of this is the ``print`` statement. The following loop
-*can* be interrupted::
-
- >>> while True:
- ... print("Hello")
-
-The typical use case for ``sig_check()`` is within tight loops doing complicated
-stuff (mixed Python and Cython code, potentially raising exceptions). It is
-reasonably safe to use and gives a lot of control, because in your Cython code,
-a ``KeyboardInterrupt`` can *only* be raised during ``sig_check()``::
-
- def sig_check_example():
- for x in foo:
- # (one loop iteration which does not take a long time)
- sig_check()
-
-This ``KeyboardInterrupt`` is treated like any other Python exception and can be
-handled as usual::
-
- def catch_interrupts():
- try:
- while some_condition():
- sig_check()
- do_something()
- except KeyboardInterrupt:
- # (handle interrupt)
-
-Of course, you can also put the ``try``/``except`` inside the loop in the
-example above.
-
-The function ``sig_check()`` is an extremely fast inline function which should
-have no measurable effect on performance.
-
-.. _section_sig_on:
-
-Using ``sig_on()`` and ``sig_off()``
-------------------------------------
-
-Another mechanism for interrupt handling is the pair of functions ``sig_on()``
-and ``sig_off()``. It is more powerful than ``sig_check()`` but also a lot more
-dangerous. You should put ``sig_on()`` *before* and ``sig_off()`` *after* any
-Cython code which could potentially take a long time. These two *must always* be
-called in **pairs**, i.e. every ``sig_on()`` must be matched by a closing
-``sig_off()``.
-
-In practice your function will probably look like::
-
- def sig_example():
- # (some harmless initialization)
- sig_on()
- # (a long computation here, potentially calling a C library)
- sig_off()
- # (some harmless post-processing)
- return something
-
-It is possible to put ``sig_on()`` and ``sig_off()`` in different functions,
-provided that ``sig_off()`` is called before the function which calls
-``sig_on()`` returns. The following code is *invalid*::
-
- # INVALID code because we return from function foo()
- # without calling sig_off() first.
- cdef foo():
- sig_on()
-
- def f1():
- foo()
- sig_off()
-
-But the following is valid since you cannot call ``foo`` interactively::
-
- cdef int foo():
- sig_off()
- return 2+2
-
- def f1():
- sig_on()
- return foo()
-
-For clarity however, it is best to avoid this.
-
-A common mistake is to put ``sig_off()`` towards the end of a function (before
-the ``return``) when the function has multiple ``return`` statements. So make
-sure there is a ``sig_off()`` before *every* ``return`` (and also before every
-``raise``).
-
-.. WARNING::
-
- The code inside ``sig_on()`` should be pure C or Cython code. If you call
- any Python code or manipulate any Python object (even something trivial like
- ``x = []``), an interrupt can mess up Python's internal state. When in
- doubt, try to use :ref:`sig_check() <section_sig_check>` instead.
-
- Also, when an interrupt occurs inside ``sig_on()``, code execution
- immediately stops without cleaning up. For example, any memory allocated
- inside ``sig_on()`` is lost. See :ref:`advanced-sig` for ways to deal with
- this.
-
-When the user presses ``CTRL-C`` inside ``sig_on()``, execution will jump back
-to ``sig_on()`` (the first one if there is a stack) and ``sig_on()`` will raise
-``KeyboardInterrupt``. As with ``sig_check()``, this exception can be handled in
-the usual way::
-
- def catch_interrupts():
- try:
- sig_on() # This must be INSIDE the try
- # (some long computation)
- sig_off()
- except KeyboardInterrupt:
- # (handle interrupt)
-
-It is possible to stack ``sig_on()`` and ``sig_off()``. If you do this, the
-effect is exactly the same as if only the outer ``sig_on()``/``sig_off()`` was
-there. The inner ones will just change a reference counter and otherwise do
-nothing. Make sure that the number of ``sig_on()`` calls equal the number of
-``sig_off()`` calls::
-
- def f1():
- sig_on()
- x = f2()
- sig_off()
-
- cdef f2():
- sig_on()
- # ...
- sig_off()
- return ans
-
-Extra care must be taken with exceptions raised inside ``sig_on()``. The problem
-is that, if you do not do anything special, the ``sig_off()`` will never be
-called if there is an exception. If you need to *raise* an exception yourself,
-call a ``sig_off()`` before it::
-
- def raising_an_exception():
- sig_on()
- # (some long computation)
- if (something_failed):
- sig_off()
- raise RuntimeError("something failed")
- # (some more computation)
- sig_off()
- return something
-
-Alternatively, you can use ``try``/``finally`` which will also catch exceptions
-raised by subroutines inside the ``try``::
-
- def try_finally_example():
- sig_on() # This must be OUTSIDE the try
- try:
- # (some long computation, potentially raising exceptions)
- return something
- finally:
- sig_off()
-
-If you want to also catch this exception, you need a nested ``try``::
-
- def try_finally_and_catch_example():
- try:
- sig_on()
- try:
- # (some long computation, potentially raising exceptions)
- finally:
- sig_off()
- except Exception:
- print "Trouble!Trouble!"
-
-``sig_on()`` is implemented using the C library call ``setjmp()`` which takes a
-very small but still measurable amount of time. In very time-critical code, one
-can conditionally call ``sig_on()`` and ``sig_off()``::
-
- def conditional_sig_on_example(long n):
- if n > 100:
- sig_on()
- # (do something depending on n)
- if n > 100:
- sig_off()
-
-This should only be needed if both the check (``n > 100`` in the example) and
-the code inside the ``sig_on()`` block take very little time.
-
-Other Signals
--------------
-
-Apart from handling interrupts, ``sig_on()`` provides more general signal
-handling. For example, it handles :func:`alarm` time-outs by raising an
-``AlarmInterrupt`` (inherited from ``KeyboardInterrupt``) exception.
-
-If the code inside ``sig_on()`` would generate a segmentation fault or call the
-C function ``abort()`` (or more generally, raise any of SIGSEGV, SIGILL,
-SIGABRT, SIGFPE, SIGBUS), this is caught by the interrupt framework and an
-exception is raised (``RuntimeError`` for SIGABRT, ``FloatingPointError`` for
-SIGFPE and the custom exception ``SignalError``, based on ``BaseException``,
-otherwise)::
-
- cdef extern from 'stdlib.h':
- void abort()
-
- def abort_example():
- sig_on()
- abort()
- sig_off()
-
-::
-
- >>> abort_example()
- Traceback (most recent call last):
- ...
- RuntimeError: Aborted
-
-This exception can be handled by a ``try``/``except`` block as explained above.
-A segmentation fault or ``abort()`` unguarded by ``sig_on()`` would simply
-terminate the Python Interpreter. This applies only to ``sig_on()``, the
-function ``sig_check()`` only deals with interrupts and alarms.
-
-Instead of ``sig_on()``, there is also a function ``sig_str(s)``, which takes a
-C string ``s`` as argument. It behaves the same as ``sig_on()``, except that the
-string ``s`` will be used as a string for the exception. ``sig_str(s)`` should
-still be closed by ``sig_off()``. Example Cython code::
-
- cdef extern from 'stdlib.h':
- void abort()
-
- def abort_example_with_sig_str():
- sig_str("custom error message")
- abort()
- sig_off()
-
-Executing this gives::
-
- >>> abort_example_with_sig_str()
- Traceback (most recent call last):
- ...
- RuntimeError: custom error message
-
-With regard to ordinary interrupts (i.e. SIGINT), ``sig_str(s)`` behaves the
-same as ``sig_on()``: a simple ``KeyboardInterrupt`` is raised.
-
-.. _sig-error:
-
-Error Handling in C Libraries
------------------------------
-
-Some C libraries can produce errors and use some sort of callback mechanism to
-report errors: an external error handling function needs to be set up which will
-be called by the C library if an error occurs.
-
-The function ``sig_error()`` can be used to deal with these errors. This
-function may only be called within a ``sig_on()`` block (otherwise the Python
-interpreter will crash hard) after raising a Python exception. You need to use
-the :ref:`Python/C API <python:exceptionhandling>` for this
-and call ``sig_error()`` after calling some variant of :c:func:`PyErr_SetObject()`.
-Even within Cython, you cannot use the ``raise`` statement, because then the
-``sig_error()`` will never be executed. The call to ``sig_error()`` will use the
-``sig_on()`` machinery such that the exception will be seen by ``sig_on()``.
-
-A typical error handler implemented in Cython would look as follows::
-
- include "cysignals/signals.pxi"
- from cpython.exc cimport PyErr_SetString
-
- cdef void error_handler(char *msg):
- PyErr_SetString(RuntimeError, msg)
- sig_error()
-
-Exceptions which are raised this way can be handled as usual by putting
-the ``sig_on()`` in a ``try``/``except`` block.
-For example, in `SageMath <http://www.sagemath.org/>`_, the
-`PARI interface <http://doc.sagemath.org/html/en/reference/libs/sage/libs/pari/pari_instance.html>`_
-can raise a custom ``PariError`` exception. This can be handled as follows::
-
- def handle_pari_error():
- try:
- sig_on() # This must be INSIDE the try
- # (call to PARI)
- sig_off()
- except PariError:
- # (handle error)
-
-SageMath uses this mechanism for libGAP, NTL and PARI.
-
-.. _advanced-sig:
-
-Advanced Functions
-------------------
-
-There are several more specialized functions for dealing with interrupts. As
-mentioned above, ``sig_on()`` makes no attempt to clean anything up (restore
-state or freeing memory) when an interrupt occurs. In fact, it would be
-impossible for ``sig_on()`` to do that. If you want to add some cleanup code,
-use ``sig_on_no_except()`` for this. This function behaves *exactly* like
-``sig_on()``, except that any exception raised (like ``KeyboardInterrupt`` or
-``RuntimeError``) is not yet passed to Python. Essentially, the exception is
-there, but we prevent Cython from looking for the exception. Then
-``cython_check_exception()`` can be used to make Cython look for the exception.
-
-Normally, ``sig_on_no_except()`` returns 1. If a signal was caught and an
-exception raised, ``sig_on_no_except()`` instead returns 0. The following
-example shows how to use ``sig_on_no_except()``::
-
- def no_except_example():
- if not sig_on_no_except():
- # (clean up messed up internal state)
-
- # Make Cython realize that there is an exception.
- # It will look like the exception was actually raised
- # by cython_check_exception().
- cython_check_exception()
- # (some long computation, messing up internal state of objects)
- sig_off()
-
-There is also a function ``sig_str_no_except(s)`` which is analogous to
-``sig_str(s)``.
-
-.. NOTE::
-
- See the file `src/cysignals/tests.pyx <https://github.com/sagemath/cysignals/blob/master/src/cysignals/tests.pyx>`_
- for more examples of how to use the various ``sig_*()`` functions.
-
-Testing Interrupts
-------------------
-
-When writing documentation, one sometimes wants to check that certain
-code can be interrupted in a clean way. The best way to do this is to
-use :func:`cysignals.alarm`.
-
-The following is an example of a doctest demonstrating that the
-SageMath function :func:`factor()` can be interrupted::
-
- >>> from cysignals.alarm import alarm, AlarmInterrupt
- >>> try:
- ... alarm(0.5)
- ... factor(10**1000 + 3)
- ... except AlarmInterrupt:
- ... print("alarm!")
- alarm!
-
-If you use the SageMath doctesting framework, you can instead doctest
-the exception in the usual way. To avoid race conditions, make sure
-that the calls to ``alarm()`` and the function you want to test are in
-the same doctest::
-
- >>> alarm(0.5); factor(10**1000 + 3)
- Traceback (most recent call last):
- ...
- AlarmInterrupt
-
-Releasing the Global Interpreter Lock (GIL)
--------------------------------------------
-
-All the functions related to interrupt and signal handling do not require the
-`Python GIL
-<http://docs.cython.org/src/userguide/external_C_code.html#acquiring-and-releasing-the-gil>`_
-(if you don't know what this means, you can safely ignore this section), they
-are declared ``nogil``. This means that they can be used in Cython code inside
-``with nogil`` blocks. If ``sig_on()`` needs to raise an exception, the GIL is
-temporarily acquired internally.
-
-If you use C libraries without the GIL and you want to raise an exception before
-calling :ref:`sig_error() <sig-error>`, remember to acquire the GIL while
-raising the exception. Within Cython, you can use a `with gil context
-<http://docs.cython.org/src/userguide/external_C_code.html#acquiring-the-gil>`_.
-
-.. WARNING::
-
- The GIL should never be released or acquired inside a ``sig_on()`` block. If
- you want to use a ``with nogil`` block, put both ``sig_on()`` and
- ``sig_off()`` inside that block. When in doubt, choose to use
- ``sig_check()`` instead, which is always safe to use.
+.. toctree::
+ pysignals
+ pselect
diff --git a/docs/source/interrupt.rst b/docs/source/interrupt.rst
new file mode 100644
index 0000000..69ea3d1
--- /dev/null
+++ b/docs/source/interrupt.rst
@@ -0,0 +1,249 @@
+.. _section_interrupt:
+
+Interrupt handling
+==================
+
+cysignals provides two related mechanisms to deal with interrupts:
+
+* Use :ref:`sig_check() <section_sig_check>` if you are writing mixed
+ Cython/Python code. Typically this is code with (nested) loops where every
+ individual statement takes little time.
+
+* Use :ref:`sig_on() and sig_off() <section_sig_on>` if you are calling external
+ C libraries or inside pure Cython code (without any Python functions) where
+ even an individual statement, like a library call, can take a long time.
+
+The functions ``sig_check()``, ``sig_on()`` and ``sig_off()`` can be put in all
+kinds of Cython functions: ``def``, ``cdef`` or ``cpdef``. You cannot put them
+in pure Python code (files with extension ``.py``).
+
+Basic example
+-------------
+
+The ``sig_check()`` in the loop below ensures that the loop can be
+interrupted by ``CTRL-C``::
+
+ from cysignals.signals cimport sig_check
+ from libc.math cimport sin
+
+ def sine_sum(double x, long count):
+ cdef double s = 0
+ for i in range(count):
+ sig_check()
+ s += sin(i*x)
+ return s
+
+See the `example <https://github.com/sagemath/cysignals/tree/master/example>`_
+directory for this complete working example.
+
+.. NOTE::
+
+ Cython ``cdef`` or ``cpdef`` functions with a return type (like ``cdef int
+ myfunc():``) need to have an `except value
+ <http://docs.cython.org/src/userguide/language_basics.html#error-return-values>`_
+ to propagate exceptions. Remember this whenever you write ``sig_check()`` or
+ ``sig_on()`` inside such a function, otherwise you will see a message like
+ ``Exception KeyboardInterrupt: KeyboardInterrupt() in <function name>
+ ignored``.
+
+.. _section_sig_check:
+
+Using ``sig_check()``
+---------------------
+
+``sig_check()`` can be used to check for pending interrupts. If an interrupt
+happens during the execution of C or Cython code, it will be caught by the next
+``sig_check()``, the next ``sig_on()`` or possibly the next Python statement.
+With the latter we mean that certain Python statements also check for
+interrupts, an example of this is the ``print`` statement. The following loop
+*can* be interrupted:
+
+.. code-block:: pycon
+
+ >>> while True:
+ ... print("Hello")
+
+The typical use case for ``sig_check()`` is within tight loops doing complicated
+stuff (mixed Python and Cython code, potentially raising exceptions). It is
+reasonably safe to use and gives a lot of control, because in your Cython code,
+a ``KeyboardInterrupt`` can *only* be raised during ``sig_check()``::
+
+ from cysignals.signals cimport sig_check
+ def sig_check_example():
+ for x in foo:
+ # (one loop iteration which does not take a long time)
+ sig_check()
+
+This ``KeyboardInterrupt`` is treated like any other Python exception and can be
+handled as usual::
+
+ from cysignals.signals cimport sig_check
+ def catch_interrupts():
+ try:
+ while some_condition():
+ sig_check()
+ do_something()
+ except KeyboardInterrupt:
+ # (handle interrupt)
+
+Of course, you can also put the ``try``/``except`` inside the loop in the
+example above.
+
+The function ``sig_check()`` is an extremely fast inline function which should
+have no measurable effect on performance.
+
+.. _section_sig_on:
+
+Using ``sig_on()`` and ``sig_off()``
+------------------------------------
+
+Another mechanism for interrupt handling is the pair of functions ``sig_on()``
+and ``sig_off()``. It is more powerful than ``sig_check()`` but also a lot more
+dangerous. You should put ``sig_on()`` *before* and ``sig_off()`` *after* any
+Cython code which could potentially take a long time. These two *must always* be
+called in **pairs**, i.e. every ``sig_on()`` must be matched by a closing
+``sig_off()``.
+
+In practice your function will probably look like::
+
+ from cysignals.signals cimport sig_on, sig_off
+ def sig_example():
+ # (some harmless initialization)
+ sig_on()
+ # (a long computation here, potentially calling a C library)
+ sig_off()
+ # (some harmless post-processing)
+ return something
+
+It is possible to put ``sig_on()`` and ``sig_off()`` in different functions,
+provided that ``sig_off()`` is called before the function which calls
+``sig_on()`` returns. The following code is *invalid*::
+
+ # INVALID code because we return from function foo()
+ # without calling sig_off() first.
+ cdef foo():
+ sig_on()
+
+ def f1():
+ foo()
+ sig_off()
+
+But the following is valid since you cannot call ``foo`` interactively::
+
+ from cysignals.signals cimport sig_on, sig_off
+
+ cdef int foo():
+ sig_off()
+ return 2+2
+
+ def f1():
+ sig_on()
+ return foo()
+
+For clarity however, it is best to avoid this.
+
+A common mistake is to put ``sig_off()`` towards the end of a function (before
+the ``return``) when the function has multiple ``return`` statements. So make
+sure there is a ``sig_off()`` before *every* ``return`` (and also before every
+``raise``).
+
+.. WARNING::
+
+ The code inside ``sig_on()`` should be pure C or Cython code. If you call
+ any Python code or manipulate any Python object (even something trivial like
+ ``x = []``), an interrupt can mess up Python's internal state. When in
+ doubt, try to use :ref:`sig_check() <section_sig_check>` instead.
+
+ Also, when an interrupt occurs inside ``sig_on()``, code execution
+ immediately stops without cleaning up. For example, any memory allocated
+ inside ``sig_on()`` is lost. See :ref:`advanced-sig` for ways to deal with
+ this.
+
+When the user presses ``CTRL-C`` inside ``sig_on()``, execution will jump back
+to ``sig_on()`` (the first one if there is a stack) and ``sig_on()`` will raise
+``KeyboardInterrupt``. As with ``sig_check()``, this exception can be handled in
+the usual way::
+
+ from cysignals.signals cimport sig_on, sig_off
+ def catch_interrupts():
+ try:
+ sig_on() # This must be INSIDE the try
+ # (some long computation)
+ sig_off()
+ except KeyboardInterrupt:
+ # (handle interrupt)
+
+It is possible to stack ``sig_on()`` and ``sig_off()``. If you do this, the
+effect is exactly the same as if only the outer ``sig_on()``/``sig_off()`` was
+there. The inner ones will just change a reference counter and otherwise do
+nothing. Make sure that the number of ``sig_on()`` calls equal the number of
+``sig_off()`` calls::
+
+ from cysignals.signals cimport sig_on, sig_off
+
+ def f1():
+ sig_on()
+ x = f2()
+ sig_off()
+
+ cdef f2():
+ sig_on()
+ # ...
+ sig_off()
+ return ans
+
+Extra care must be taken with exceptions raised inside ``sig_on()``. The problem
+is that, if you do not do anything special, the ``sig_off()`` will never be
+called if there is an exception. If you need to *raise* an exception yourself,
+call a ``sig_off()`` before it::
+
+ from cysignals.signals cimport sig_on, sig_off
+ def raising_an_exception():
+ sig_on()
+ # (some long computation)
+ if (something_failed):
+ sig_off()
+ raise RuntimeError("something failed")
+ # (some more computation)
+ sig_off()
+ return something
+
+Alternatively, you can use ``try``/``finally`` which will also catch exceptions
+raised by subroutines inside the ``try``::
+
+ from cysignals.signals cimport sig_on, sig_off
+ def try_finally_example():
+ sig_on() # This must be OUTSIDE the try
+ try:
+ # (some long computation, potentially raising exceptions)
+ return something
+ finally:
+ sig_off()
+
+If you want to also catch this exception, you need a nested ``try``::
+
+ from cysignals.signals cimport sig_on, sig_off
+ def try_finally_and_catch_example():
+ try:
+ sig_on()
+ try:
+ # (some long computation, potentially raising exceptions)
+ finally:
+ sig_off()
+ except Exception:
+ print("Trouble! Trouble!")
+
+``sig_on()`` is implemented using the C library call ``setjmp()`` which takes a
+very small but still measurable amount of time. In very time-critical code, one
+can conditionally call ``sig_on()`` and ``sig_off()``::
+
+ from cysignals.signals cimport sig_on, sig_off
+ def conditional_sig_on_example(long n):
+ if n > 100:
+ sig_on()
+ # (do something depending on n)
+ if n > 100:
+ sig_off()
+
+This should only be needed if both the check (``n > 100`` in the example) and
+the code inside the ``sig_on()`` block take very little time.
diff --git a/docs/source/pselect.rst b/docs/source/pselect.rst
new file mode 100644
index 0000000..84c16ef
--- /dev/null
+++ b/docs/source/pselect.rst
@@ -0,0 +1,3 @@
+.. automodule:: cysignals.pselect
+ :members:
+ :special-members: __enter__, __exit__
diff --git a/docs/source/pysignals.rst b/docs/source/pysignals.rst
new file mode 100644
index 0000000..5266319
--- /dev/null
+++ b/docs/source/pysignals.rst
... 1700 lines suppressed ...
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/cysignals.git
More information about the Python-modules-commits
mailing list