]> granicus.if.org Git - python/commitdiff
Issue #14456: improve documentation of the signal module w.r.t. threads.
authorAntoine Pitrou <solipsis@pitrou.net>
Sat, 31 Mar 2012 19:09:00 +0000 (21:09 +0200)
committerAntoine Pitrou <solipsis@pitrou.net>
Sat, 31 Mar 2012 19:09:00 +0000 (21:09 +0200)
1  2 
Doc/library/signal.rst

index 04afd9e8a4ed79e7af193da8c6fbc11ee8113e86,d1cae13d62e61fb7c9a20be9e54518747375f959..f3ac55b554142cfa7351508ddeb136ab8e5a0c05
@@@ -5,43 -5,58 +5,61 @@@
     :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:
- * 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.
- * 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.
- * Because the C signal handler always returns, it makes little sense to catch
-   synchronous errors like :const:`SIGFPE` or :const:`SIGSEGV`.
- * 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.
- * 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.
+ This module provides mechanisms to use signal handlers in Python.
+ General rules
+ -------------
+ 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.
+ 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.
+ There is no way to "block" signals temporarily from critical sections (since
+ this is not supported by all Unix flavors).
+ 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:
  
@@@ -183,60 -172,6 +201,65 @@@ The :mod:`signal` module defines the fo
     will then be called.  Returns nothing.  Not on Windows. (See the Unix man page
     :manpage:`signal(2)`.)
  
-    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.
 +   See also :func:`sigwait`, :func:`sigwaitinfo`, :func:`sigtimedwait` and
 +   :func:`sigpending`.
 +
 +
 +.. function:: pthread_kill(thread_id, signum)
 +
-    attribute of :attr:`threading.Thread` to get a 'thread identifier' for
-    *thread_id*.
++   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`
-    performed; this can be used to check if a thread is still running.
++   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 the target thread is still running.
 +
 +   Availability: Unix (see the man page :manpage:`pthread_kill(3)` for further
 +   information).
 +
 +   See also :func:`os.kill`.
 +
 +   .. versionadded:: 3.3
 +
 +
 +.. function:: pthread_sigmask(how, mask)
 +
 +   Fetch and/or change the signal mask of the calling thread.  The signal mask
 +   is the set of signals whose delivery is currently blocked for the caller.
 +   Return the old signal mask as a set of signals.
 +
 +   The behavior of the call is dependent on the value of *how*, as follows.
 +
 +    * :data:`SIG_BLOCK`: The set of blocked signals is the union of the current
 +      set and the *mask* argument.
 +    * :data:`SIG_UNBLOCK`: The signals in *mask* are removed from the current
 +      set of blocked signals.  It is permissible to attempt to unblock a
 +      signal which is not blocked.
 +    * :data:`SIG_SETMASK`: The set of blocked signals is set to the *mask*
 +      argument.
 +
 +   *mask* is a set of signal numbers (e.g. {:const:`signal.SIGINT`,
 +   :const:`signal.SIGTERM`}). Use ``range(1, signal.NSIG)`` for a full mask
 +   including all signals.
 +
 +   For example, ``signal.pthread_sigmask(signal.SIG_BLOCK, [])`` reads the
 +   signal mask of the calling thread.
 +
 +   Availability: Unix. See the man page :manpage:`sigprocmask(3)` and
 +   :manpage:`pthread_sigmask(3)` for further information.
 +
 +   See also :func:`pause`, :func:`sigpending` and :func:`sigwait`.
 +
 +   .. versionadded:: 3.3
 +
  
  .. function:: setitimer(which, seconds[, interval])