Commits

Antoine Pitrou  committed 44d13f3 Merge

Issue #14456: improve documentation of the signal module w.r.t. threads.

  • Participants
  • Parent commits 2c14325, 52e32f3

Comments (0)

Files changed (1)

File Doc/library/signal.rst

    :synopsis: Set handlers for asynchronous events.
 
 
-This module provides mechanisms to use signal handlers in Python. Some general
-rules for working with signals and their handlers:
+This module provides mechanisms to use signal handlers in Python.
 
-* A handler for a particular signal, once set, remains installed until it is
-  explicitly reset (Python emulates the BSD style interface regardless of the
-  underlying implementation), with the exception of the handler for
-  :const:`SIGCHLD`, which follows the underlying implementation.
 
-* Although Python signal handlers are called asynchronously as far as the Python
-  user is concerned, they can only occur between the "atomic" instructions of the
-  Python interpreter.  This means that signals arriving during long calculations
-  implemented purely in C (such as regular expression matches on large bodies of
-  text) may be delayed for an arbitrary amount of time.
+General rules
+-------------
 
-* When a signal arrives during an I/O operation, it is possible that the I/O
-  operation raises an exception after the signal handler returns. This is
-  dependent on the underlying Unix system's semantics regarding interrupted system
-  calls.
+The :func:`signal.signal` function allows to define custom handlers to be
+executed when a signal is received.  A small number of default handlers are
+installed: :const:`SIGPIPE` is ignored (so write errors on pipes and sockets
+can be reported as ordinary Python exceptions) and :const:`SIGINT` is
+translated into a :exc:`KeyboardInterrupt` exception.
 
-* Because the C signal handler always returns, it makes little sense to catch
-  synchronous errors like :const:`SIGFPE` or :const:`SIGSEGV`.
+A handler for a particular signal, once set, remains installed until it is
+explicitly reset (Python emulates the BSD style interface regardless of the
+underlying implementation), with the exception of the handler for
+:const:`SIGCHLD`, which follows the underlying implementation.
 
-* Python installs a small number of signal handlers by default: :const:`SIGPIPE`
-  is ignored (so write errors on pipes and sockets can be reported as ordinary
-  Python exceptions) and :const:`SIGINT` is translated into a
-  :exc:`KeyboardInterrupt` exception.  All of these can be overridden.
+There is no way to "block" signals temporarily from critical sections (since
+this is not supported by all Unix flavors).
 
-* Some care must be taken if both signals and threads are used in the same
-  program.  The fundamental thing to remember in using signals and threads
-  simultaneously is: always perform :func:`signal` operations in the main thread
-  of execution.  Any thread can perform an :func:`alarm`, :func:`getsignal`,
-  :func:`pause`, :func:`setitimer` or :func:`getitimer`; only the main thread
-  can set a new signal handler, and the main thread will be the only one to
-  receive signals (this is enforced by the Python :mod:`signal` module, even
-  if the underlying thread implementation supports sending signals to
-  individual threads).  This means that signals can't be used as a means of
-  inter-thread communication.  Use locks instead.
+
+Execution of Python signal handlers
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+A Python signal handler does not get executed inside the low-level (C) signal
+handler.  Instead, the low-level signal handler sets a flag which tells the
+:term:`virtual machine` to execute the corresponding Python signal handler
+at a later point(for example at the next :term:`bytecode` instruction).
+This has consequences:
+
+* It makes little sense to catch synchronous errors like :const:`SIGFPE` or
+  :const:`SIGSEGV`.
+
+* A long-running calculation implemented purely in C (such as regular
+  expression matching on a large body of text) may run uninterrupted for an
+  arbitrary amount of time, regardless of any signals received.  The Python
+  signal handlers will be called when the calculation finishes.
+
+
+.. _signals-and-threads:
+
+
+Signals and threads
+^^^^^^^^^^^^^^^^^^^
+
+Python signal handlers are always executed in the main Python thread,
+even if the signal was received in another thread.  This means that signals
+can't be used as a means of inter-thread communication.  You can use
+the synchronization primitives from the :mod:`threading` module instead.
+
+Besides, only the main thread is allowed to set a new signal handler.
+
+
+Module contents
+---------------
 
 The variables defined in the :mod:`signal` module are:
 
 
 .. function:: pthread_kill(thread_id, signum)
 
-   Send the signal *signum* to the thread *thread_id*, another thread in the same
-   process as the caller.  The signal is asynchronously directed to thread.
+   Send the signal *signum* to the thread *thread_id*, another thread in the
+   same process as the caller.  The target thread can be executing any code
+   (Python or not).  However, if the target thread is executing the Python
+   interpreter, the Python signal handlers will be :ref:`executed by the main
+   thread <signals-and-threads>`.  Therefore, the only point of sending a signal to a particular
+   Python thread would be to force a running system call to fail with
+   :exc:`InterruptedError`.
 
    Use :func:`threading.get_ident()` or the :attr:`~threading.Thread.ident`
-   attribute of :attr:`threading.Thread` to get a 'thread identifier' for
-   *thread_id*.
+   attribute of :class:`threading.Thread` objects to get a suitable value
+   for *thread_id*.
 
    If *signum* is 0, then no signal is sent, but error checking is still
-   performed; this can be used to check if a thread is still running.
+   performed; this can be used to check if the target thread is still running.
 
    Availability: Unix (see the man page :manpage:`pthread_kill(3)` for further
    information).