[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