.. versionadded:: 3.8
+.. function:: valid_signals()
+
+ Return the set of valid signal numbers on this platform. This can be
+ less than ``range(1, NSIG)`` if some signals are reserved by the system
+ for internal use.
+
+ .. versionadded:: 3.8
+
+
.. function:: pause()
Cause the process to sleep until a signal is received; the appropriate handler
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.
+ :const:`signal.SIGTERM`}). Use :func:`~signal.valid_signals` for a full
+ mask including all signals.
For example, ``signal.pthread_sigmask(signal.SIG_BLOCK, [])`` reads the
signal mask of the calling thread.
if not isinstance(sig, int):
raise TypeError(f'sig must be an int, not {sig!r}')
- if not (1 <= sig < signal.NSIG):
- raise ValueError(f'sig {sig} out of range(1, {signal.NSIG})')
+ if sig not in signal.valid_signals():
+ raise ValueError(f'invalid signal number {sig}')
def _make_read_pipe_transport(self, pipe, protocol, waiter=None,
extra=None):
def _serve(self):
if hasattr(signal, 'pthread_sigmask'):
- signal.pthread_sigmask(signal.SIG_BLOCK, range(1, signal.NSIG))
+ signal.pthread_sigmask(signal.SIG_BLOCK, signal.valid_signals())
while 1:
try:
with self._listener.accept() as conn:
if 'sigpending' in _globals:
@_wraps(_signal.sigpending)
def sigpending():
- sigs = _signal.sigpending()
- return set(_int_to_enum(x, Signals) for x in sigs)
+ return {_int_to_enum(x, Signals) for x in _signal.sigpending()}
if 'sigwait' in _globals:
return _int_to_enum(retsig, Signals)
sigwait.__doc__ = _signal.sigwait
+
+if 'valid_signals' in _globals:
+ @_wraps(_signal.valid_signals)
+ def valid_signals():
+ return {_int_to_enum(x, Signals) for x in _signal.valid_signals()}
+
+
del _globals, _wraps
def __init__(self):
import signal
self.signal = signal
- self.signals = list(range(1, signal.NSIG))
+ self.signals = signal.valid_signals()
# SIGKILL and SIGSTOP signals cannot be ignored nor caught
for signame in ('SIGKILL', 'SIGSTOP'):
try:
@mock.patch('asyncio.unix_events.signal')
def test_add_signal_handler_setup_error(self, m_signal):
m_signal.NSIG = signal.NSIG
+ m_signal.valid_signals = signal.valid_signals
m_signal.set_wakeup_fd.side_effect = ValueError
self.assertRaises(
@mock.patch('asyncio.unix_events.signal')
def test_add_signal_handler(self, m_signal):
m_signal.NSIG = signal.NSIG
+ m_signal.valid_signals = signal.valid_signals
cb = lambda: True
self.loop.add_signal_handler(signal.SIGHUP, cb)
@mock.patch('asyncio.unix_events.signal')
def test_add_signal_handler_install_error(self, m_signal):
m_signal.NSIG = signal.NSIG
+ m_signal.valid_signals = signal.valid_signals
def set_wakeup_fd(fd):
if fd == -1:
@mock.patch('asyncio.base_events.logger')
def test_add_signal_handler_install_error2(self, m_logging, m_signal):
m_signal.NSIG = signal.NSIG
+ m_signal.valid_signals = signal.valid_signals
class Err(OSError):
errno = errno.EINVAL
errno = errno.EINVAL
m_signal.signal.side_effect = Err
m_signal.NSIG = signal.NSIG
+ m_signal.valid_signals = signal.valid_signals
self.assertRaises(
RuntimeError,
@mock.patch('asyncio.unix_events.signal')
def test_remove_signal_handler(self, m_signal):
m_signal.NSIG = signal.NSIG
+ m_signal.valid_signals = signal.valid_signals
self.loop.add_signal_handler(signal.SIGHUP, lambda: True)
def test_remove_signal_handler_2(self, m_signal):
m_signal.NSIG = signal.NSIG
m_signal.SIGINT = signal.SIGINT
+ m_signal.valid_signals = signal.valid_signals
self.loop.add_signal_handler(signal.SIGINT, lambda: True)
self.loop._signal_handlers[signal.SIGHUP] = object()
@mock.patch('asyncio.base_events.logger')
def test_remove_signal_handler_cleanup_error(self, m_logging, m_signal):
m_signal.NSIG = signal.NSIG
+ m_signal.valid_signals = signal.valid_signals
self.loop.add_signal_handler(signal.SIGHUP, lambda: True)
m_signal.set_wakeup_fd.side_effect = ValueError
@mock.patch('asyncio.unix_events.signal')
def test_remove_signal_handler_error(self, m_signal):
m_signal.NSIG = signal.NSIG
+ m_signal.valid_signals = signal.valid_signals
self.loop.add_signal_handler(signal.SIGHUP, lambda: True)
m_signal.signal.side_effect = OSError
@mock.patch('asyncio.unix_events.signal')
def test_remove_signal_handler_error2(self, m_signal):
m_signal.NSIG = signal.NSIG
+ m_signal.valid_signals = signal.valid_signals
self.loop.add_signal_handler(signal.SIGHUP, lambda: True)
class Err(OSError):
@mock.patch('asyncio.unix_events.signal')
def test_close(self, m_signal):
m_signal.NSIG = signal.NSIG
+ m_signal.valid_signals = signal.valid_signals
self.loop.add_signal_handler(signal.SIGHUP, lambda: True)
self.loop.add_signal_handler(signal.SIGCHLD, lambda: True)
@mock.patch('asyncio.unix_events.signal')
def test_close_on_finalizing(self, m_signal, m_sys):
m_signal.NSIG = signal.NSIG
+ m_signal.valid_signals = signal.valid_signals
self.loop.add_signal_handler(signal.SIGHUP, lambda: True)
self.assertEqual(len(self.loop._signal_handlers), 1)
script = os.path.join(dirname, 'signalinterproctester.py')
assert_python_ok(script)
+ def test_valid_signals(self):
+ s = signal.valid_signals()
+ self.assertIsInstance(s, set)
+ self.assertIn(signal.Signals.SIGINT, s)
+ self.assertIn(signal.Signals.SIGALRM, s)
+ self.assertNotIn(0, s)
+ self.assertNotIn(signal.NSIG, s)
+ self.assertLess(len(s), signal.NSIG)
+
@unittest.skipUnless(sys.platform == "win32", "Windows specific")
class WindowsSignalTests(unittest.TestCase):
+
+ def test_valid_signals(self):
+ s = signal.valid_signals()
+ self.assertIsInstance(s, set)
+ self.assertGreaterEqual(len(s), 6)
+ self.assertIn(signal.Signals.SIGINT, s)
+ self.assertNotIn(0, s)
+ self.assertNotIn(signal.NSIG, s)
+ self.assertLess(len(s), signal.NSIG)
+
def test_issue9324(self):
# Updated for issue #10003, adding SIGBREAK
handler = lambda x, y: None
self.assertRaises(TypeError, signal.pthread_sigmask, 1)
self.assertRaises(TypeError, signal.pthread_sigmask, 1, 2, 3)
self.assertRaises(OSError, signal.pthread_sigmask, 1700, [])
+ with self.assertRaises(ValueError):
+ signal.pthread_sigmask(signal.SIG_BLOCK, [signal.NSIG])
+
+ @unittest.skipUnless(hasattr(signal, 'pthread_sigmask'),
+ 'need signal.pthread_sigmask()')
+ def test_pthread_sigmask_valid_signals(self):
+ s = signal.pthread_sigmask(signal.SIG_BLOCK, signal.valid_signals())
+ self.addCleanup(signal.pthread_sigmask, signal.SIG_SETMASK, s)
+ # Get current blocked set
+ s = signal.pthread_sigmask(signal.SIG_UNBLOCK, signal.valid_signals())
+ self.assertLessEqual(s, signal.valid_signals())
@unittest.skipUnless(hasattr(signal, 'pthread_sigmask'),
'need signal.pthread_sigmask()')
--- /dev/null
+Add ``signal.valid_signals()`` to expose the POSIX sigfillset()
+functionality.
#endif /* defined(HAVE_SIGWAIT) */
+#if (defined(HAVE_SIGFILLSET) || defined(MS_WINDOWS))
+
+PyDoc_STRVAR(signal_valid_signals__doc__,
+"valid_signals($module, /)\n"
+"--\n"
+"\n"
+"Return a set of valid signal numbers on this platform.\n"
+"\n"
+"The signal numbers returned by this function can be safely passed to\n"
+"functions like `pthread_sigmask`.");
+
+#define SIGNAL_VALID_SIGNALS_METHODDEF \
+ {"valid_signals", (PyCFunction)signal_valid_signals, METH_NOARGS, signal_valid_signals__doc__},
+
+static PyObject *
+signal_valid_signals_impl(PyObject *module);
+
+static PyObject *
+signal_valid_signals(PyObject *module, PyObject *Py_UNUSED(ignored))
+{
+ return signal_valid_signals_impl(module);
+}
+
+#endif /* (defined(HAVE_SIGFILLSET) || defined(MS_WINDOWS)) */
+
#if defined(HAVE_SIGWAITINFO)
PyDoc_STRVAR(signal_sigwaitinfo__doc__,
#define SIGNAL_SIGWAIT_METHODDEF
#endif /* !defined(SIGNAL_SIGWAIT_METHODDEF) */
+#ifndef SIGNAL_VALID_SIGNALS_METHODDEF
+ #define SIGNAL_VALID_SIGNALS_METHODDEF
+#endif /* !defined(SIGNAL_VALID_SIGNALS_METHODDEF) */
+
#ifndef SIGNAL_SIGWAITINFO_METHODDEF
#define SIGNAL_SIGWAITINFO_METHODDEF
#endif /* !defined(SIGNAL_SIGWAITINFO_METHODDEF) */
#ifndef SIGNAL_PTHREAD_KILL_METHODDEF
#define SIGNAL_PTHREAD_KILL_METHODDEF
#endif /* !defined(SIGNAL_PTHREAD_KILL_METHODDEF) */
-/*[clinic end generated code: output=7b41486acf93aa8e input=a9049054013a1b77]*/
+/*[clinic end generated code: output=f35d79e0cfee3f1b input=a9049054013a1b77]*/
if (signum == -1 && PyErr_Occurred())
goto error;
if (0 < signum && signum < NSIG) {
- /* bpo-33329: ignore sigaddset() return value as it can fail
- * for some reserved signals, but we want the `range(1, NSIG)`
- * idiom to allow selecting all valid signals.
- */
- (void) sigaddset(mask, (int)signum);
+ if (sigaddset(mask, (int)signum)) {
+ if (errno != EINVAL) {
+ /* Probably impossible */
+ PyErr_SetFromErrno(PyExc_OSError);
+ goto error;
+ }
+ /* For backwards compatibility, allow idioms such as
+ * `range(1, NSIG)` but warn about invalid signal numbers
+ */
+ const char *msg =
+ "invalid signal number %ld, please use valid_signals()";
+ if (PyErr_WarnFormat(PyExc_RuntimeWarning, 1, msg, signum)) {
+ goto error;
+ }
+ }
}
else {
PyErr_Format(PyExc_ValueError,
#endif /* #ifdef HAVE_SIGWAIT */
+#if defined(HAVE_SIGFILLSET) || defined(MS_WINDOWS)
+
+/*[clinic input]
+signal.valid_signals
+
+Return a set of valid signal numbers on this platform.
+
+The signal numbers returned by this function can be safely passed to
+functions like `pthread_sigmask`.
+[clinic start generated code]*/
+
+static PyObject *
+signal_valid_signals_impl(PyObject *module)
+/*[clinic end generated code: output=1609cffbcfcf1314 input=86a3717ff25288f2]*/
+{
+#ifdef MS_WINDOWS
+#ifdef SIGBREAK
+ PyObject *tup = Py_BuildValue("(iiiiiii)", SIGABRT, SIGBREAK, SIGFPE,
+ SIGILL, SIGINT, SIGSEGV, SIGTERM);
+#else
+ PyObject *tup = Py_BuildValue("(iiiiii)", SIGABRT, SIGFPE, SIGILL,
+ SIGINT, SIGSEGV, SIGTERM);
+#endif
+ if (tup == NULL) {
+ return NULL;
+ }
+ PyObject *set = PySet_New(tup);
+ Py_DECREF(tup);
+ return set;
+#else
+ sigset_t mask;
+ if (sigemptyset(&mask) || sigfillset(&mask)) {
+ return PyErr_SetFromErrno(PyExc_OSError);
+ }
+ return sigset_to_set(mask);
+#endif
+}
+
+#endif /* #if defined(HAVE_SIGFILLSET) || defined(MS_WINDOWS) */
+
+
#if defined(HAVE_SIGWAITINFO) || defined(HAVE_SIGTIMEDWAIT)
static int initialized;
static PyStructSequence_Field struct_siginfo_fields[] = {
SIGNAL_SIGWAIT_METHODDEF
SIGNAL_SIGWAITINFO_METHODDEF
SIGNAL_SIGTIMEDWAIT_METHODDEF
+#if defined(HAVE_SIGFILLSET) || defined(MS_WINDOWS)
+ SIGNAL_VALID_SIGNALS_METHODDEF
+#endif
{NULL, NULL} /* sentinel */
};
-# generated automatically by aclocal 1.15.1 -*- Autoconf -*-
+# generated automatically by aclocal 1.15 -*- Autoconf -*-
-# Copyright (C) 1996-2017 Free Software Foundation, Inc.
+# Copyright (C) 1996-2014 Free Software Foundation, Inc.
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# PARTICULAR PURPOSE.
m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])])
-# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*-
-# serial 12 (pkg-config-0.29.2)
-
+dnl pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*-
+dnl serial 11 (pkg-config-0.29.1)
+dnl
dnl Copyright © 2004 Scott James Remnant <scott@netsplit.com>.
dnl Copyright © 2012-2015 Dan Nicholson <dbn.lists@gmail.com>
dnl
dnl See the "Since" comment for each macro you use to see what version
dnl of the macros you require.
m4_defun([PKG_PREREQ],
-[m4_define([PKG_MACROS_VERSION], [0.29.2])
+[m4_define([PKG_MACROS_VERSION], [0.29.1])
m4_if(m4_version_compare(PKG_MACROS_VERSION, [$1]), -1,
[m4_fatal([pkg.m4 version $1 or higher is required but ]PKG_MACROS_VERSION[ found])])
])dnl PKG_PREREQ
AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl
pkg_failed=no
-AC_MSG_CHECKING([for $2])
+AC_MSG_CHECKING([for $1])
_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2])
_PKG_CONFIG([$1][_LIBS], [libs], [$2])
See the pkg-config man page for more details.])
if test $pkg_failed = yes; then
- AC_MSG_RESULT([no])
+ AC_MSG_RESULT([no])
_PKG_SHORT_ERRORS_SUPPORTED
if test $_pkg_short_errors_supported = yes; then
$1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1`
- else
+ else
$1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1`
fi
# Put the nasty error message in config.log where it belongs
_PKG_TEXT])[]dnl
])
elif test $pkg_failed = untried; then
- AC_MSG_RESULT([no])
+ AC_MSG_RESULT([no])
m4_default([$4], [AC_MSG_FAILURE(
[The pkg-config script could not be found or is too old. Make sure it
is in your PATH or set the PKG_CONFIG environment variable to the full
setlocale setregid setreuid setresuid setresgid setsid setpgid setpgrp setpriority setuid setvbuf \
sched_get_priority_max sched_setaffinity sched_setscheduler sched_setparam \
sched_rr_get_interval \
- sigaction sigaltstack siginterrupt sigpending sigrelse \
+ sigaction sigaltstack sigfillset siginterrupt sigpending sigrelse \
sigtimedwait sigwait sigwaitinfo snprintf strftime strlcpy symlinkat sync \
sysconf tcgetpgrp tcsetpgrp tempnam timegm times tmpfile tmpnam tmpnam_r \
truncate uname unlinkat unsetenv utimensat utimes waitid waitpid wait3 wait4 \
setlocale setregid setreuid setresuid setresgid setsid setpgid setpgrp setpriority setuid setvbuf \
sched_get_priority_max sched_setaffinity sched_setscheduler sched_setparam \
sched_rr_get_interval \
- sigaction sigaltstack siginterrupt sigpending sigrelse \
+ sigaction sigaltstack sigfillset siginterrupt sigpending sigrelse \
sigtimedwait sigwait sigwaitinfo snprintf strftime strlcpy symlinkat sync \
sysconf tcgetpgrp tcsetpgrp tempnam timegm times tmpfile tmpnam tmpnam_r \
truncate uname unlinkat unsetenv utimensat utimes waitid waitpid wait3 wait4 \
/* Define to 1 if you have the `sigaltstack' function. */
#undef HAVE_SIGALTSTACK
+/* Define to 1 if you have the `sigfillset' function. */
+#undef HAVE_SIGFILLSET
+
/* Define to 1 if `si_band' is a member of `siginfo_t'. */
#undef HAVE_SIGINFO_T_SI_BAND