From: Antoine Pitrou Date: Sat, 31 Mar 2012 19:09:00 +0000 (+0200) Subject: Issue #14456: improve documentation of the signal module w.r.t. threads. X-Git-Tag: v3.3.0a2~12 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=682d443e011a213ba577c6eed3a9c67508cc039e;p=python Issue #14456: improve documentation of the signal module w.r.t. threads. --- 682d443e011a213ba577c6eed3a9c67508cc039e diff --cc Doc/library/signal.rst index 04afd9e8a4,d1cae13d62..f3ac55b554 --- a/Doc/library/signal.rst +++ b/Doc/library/signal.rst @@@ -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)`.) + See also :func:`sigwait`, :func:`sigwaitinfo`, :func:`sigtimedwait` and + :func:`sigpending`. + + +.. 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 `. 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). + + 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])