460 lines
14 KiB
Diff
460 lines
14 KiB
Diff
From cc17fe8bed98cae0bcb7739c953933d1f379dd12 Mon Sep 17 00:00:00 2001
|
|
From: Serhiy Storchaka <storchaka@gmail.com>
|
|
Date: Tue, 8 May 2018 07:48:50 +0300
|
|
Subject: [PATCH] bpo-33441: Make the sigset_t converter available in other
|
|
modules. (GH-6720)
|
|
|
|
* Expose the sigset_t converter via private API _Py_Sigset_Converter().
|
|
* Use Argument Clinic for parsing sigset_t in signalmodule.c.
|
|
* Raise ValueError instead OverflowError for integers out of
|
|
the C long range.
|
|
|
|
Based on patch by Pablo Galindo Salgado.
|
|
|
|
Conflict:NA
|
|
Reference:https://github.com/python/cpython/commit/d54cfb160c626626394e2f171d3ccfe03309f34e
|
|
|
|
Signed-off-by: hanxinke <hanxinke@huawei.com>
|
|
---
|
|
Lib/test/test_signal.py | 4 ++
|
|
Modules/clinic/signalmodule.c.h | 53 +++++++++++---
|
|
Modules/posixmodule.c | 59 ++++++++++++++++
|
|
Modules/posixmodule.h | 9 +++
|
|
Modules/signalmodule.c | 120 +++++++-------------------------
|
|
5 files changed, 141 insertions(+), 104 deletions(-)
|
|
|
|
diff --git a/Lib/test/test_signal.py b/Lib/test/test_signal.py
|
|
index 0244650..152f803 100644
|
|
--- a/Lib/test/test_signal.py
|
|
+++ b/Lib/test/test_signal.py
|
|
@@ -962,6 +962,10 @@ class PendingSignalsTests(unittest.TestCase):
|
|
self.assertRaises(OSError, signal.pthread_sigmask, 1700, [])
|
|
with self.assertRaises(ValueError):
|
|
signal.pthread_sigmask(signal.SIG_BLOCK, [signal.NSIG])
|
|
+ with self.assertRaises(ValueError):
|
|
+ signal.pthread_sigmask(signal.SIG_BLOCK, [0])
|
|
+ with self.assertRaises(ValueError):
|
|
+ signal.pthread_sigmask(signal.SIG_BLOCK, [1<<1000])
|
|
|
|
@unittest.skipUnless(hasattr(signal, 'pthread_sigmask'),
|
|
'need signal.pthread_sigmask()')
|
|
diff --git a/Modules/clinic/signalmodule.c.h b/Modules/clinic/signalmodule.c.h
|
|
index ac97e80..811b252 100644
|
|
--- a/Modules/clinic/signalmodule.c.h
|
|
+++ b/Modules/clinic/signalmodule.c.h
|
|
@@ -248,17 +248,17 @@ PyDoc_STRVAR(signal_pthread_sigmask__doc__,
|
|
{"pthread_sigmask", (PyCFunction)signal_pthread_sigmask, METH_FASTCALL, signal_pthread_sigmask__doc__},
|
|
|
|
static PyObject *
|
|
-signal_pthread_sigmask_impl(PyObject *module, int how, PyObject *mask);
|
|
+signal_pthread_sigmask_impl(PyObject *module, int how, sigset_t mask);
|
|
|
|
static PyObject *
|
|
signal_pthread_sigmask(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
|
|
{
|
|
PyObject *return_value = NULL;
|
|
int how;
|
|
- PyObject *mask;
|
|
+ sigset_t mask;
|
|
|
|
- if (!_PyArg_ParseStack(args, nargs, "iO:pthread_sigmask",
|
|
- &how, &mask)) {
|
|
+ if (!_PyArg_ParseStack(args, nargs, "iO&:pthread_sigmask",
|
|
+ &how, _Py_Sigset_Converter, &mask)) {
|
|
goto exit;
|
|
}
|
|
return_value = signal_pthread_sigmask_impl(module, how, mask);
|
|
@@ -309,6 +309,24 @@ PyDoc_STRVAR(signal_sigwait__doc__,
|
|
#define SIGNAL_SIGWAIT_METHODDEF \
|
|
{"sigwait", (PyCFunction)signal_sigwait, METH_O, signal_sigwait__doc__},
|
|
|
|
+static PyObject *
|
|
+signal_sigwait_impl(PyObject *module, sigset_t sigset);
|
|
+
|
|
+static PyObject *
|
|
+signal_sigwait(PyObject *module, PyObject *arg)
|
|
+{
|
|
+ PyObject *return_value = NULL;
|
|
+ sigset_t sigset;
|
|
+
|
|
+ if (!PyArg_Parse(arg, "O&:sigwait", _Py_Sigset_Converter, &sigset)) {
|
|
+ goto exit;
|
|
+ }
|
|
+ return_value = signal_sigwait_impl(module, sigset);
|
|
+
|
|
+exit:
|
|
+ return return_value;
|
|
+}
|
|
+
|
|
#endif /* defined(HAVE_SIGWAIT) */
|
|
|
|
#if (defined(HAVE_SIGFILLSET) || defined(MS_WINDOWS))
|
|
@@ -349,6 +367,24 @@ PyDoc_STRVAR(signal_sigwaitinfo__doc__,
|
|
#define SIGNAL_SIGWAITINFO_METHODDEF \
|
|
{"sigwaitinfo", (PyCFunction)signal_sigwaitinfo, METH_O, signal_sigwaitinfo__doc__},
|
|
|
|
+static PyObject *
|
|
+signal_sigwaitinfo_impl(PyObject *module, sigset_t sigset);
|
|
+
|
|
+static PyObject *
|
|
+signal_sigwaitinfo(PyObject *module, PyObject *arg)
|
|
+{
|
|
+ PyObject *return_value = NULL;
|
|
+ sigset_t sigset;
|
|
+
|
|
+ if (!PyArg_Parse(arg, "O&:sigwaitinfo", _Py_Sigset_Converter, &sigset)) {
|
|
+ goto exit;
|
|
+ }
|
|
+ return_value = signal_sigwaitinfo_impl(module, sigset);
|
|
+
|
|
+exit:
|
|
+ return return_value;
|
|
+}
|
|
+
|
|
#endif /* defined(HAVE_SIGWAITINFO) */
|
|
|
|
#if defined(HAVE_SIGTIMEDWAIT)
|
|
@@ -365,19 +401,18 @@ PyDoc_STRVAR(signal_sigtimedwait__doc__,
|
|
{"sigtimedwait", (PyCFunction)signal_sigtimedwait, METH_FASTCALL, signal_sigtimedwait__doc__},
|
|
|
|
static PyObject *
|
|
-signal_sigtimedwait_impl(PyObject *module, PyObject *sigset,
|
|
+signal_sigtimedwait_impl(PyObject *module, sigset_t sigset,
|
|
PyObject *timeout_obj);
|
|
|
|
static PyObject *
|
|
signal_sigtimedwait(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
|
|
{
|
|
PyObject *return_value = NULL;
|
|
- PyObject *sigset;
|
|
+ sigset_t sigset;
|
|
PyObject *timeout_obj;
|
|
|
|
- if (!_PyArg_UnpackStack(args, nargs, "sigtimedwait",
|
|
- 2, 2,
|
|
- &sigset, &timeout_obj)) {
|
|
+ if (!_PyArg_ParseStack(args, nargs, "O&O:sigtimedwait",
|
|
+ _Py_Sigset_Converter, &sigset, &timeout_obj)) {
|
|
goto exit;
|
|
}
|
|
return_value = signal_sigtimedwait_impl(module, sigset, timeout_obj);
|
|
diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c
|
|
index 441c82e..5689f93 100644
|
|
--- a/Modules/posixmodule.c
|
|
+++ b/Modules/posixmodule.c
|
|
@@ -1278,6 +1278,65 @@ PyLong_FromPy_off_t(Py_off_t offset)
|
|
#endif
|
|
}
|
|
|
|
+#ifdef HAVE_SIGSET_T
|
|
+/* Convert an iterable of integers to a sigset.
|
|
+ Return 1 on success, return 0 and raise an exception on error. */
|
|
+int
|
|
+_Py_Sigset_Converter(PyObject *obj, void *addr)
|
|
+{
|
|
+ sigset_t *mask = (sigset_t *)addr;
|
|
+ PyObject *iterator, *item;
|
|
+ long signum;
|
|
+ int overflow;
|
|
+
|
|
+ if (sigemptyset(mask)) {
|
|
+ /* Probably only if mask == NULL. */
|
|
+ PyErr_SetFromErrno(PyExc_OSError);
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ iterator = PyObject_GetIter(obj);
|
|
+ if (iterator == NULL) {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ while ((item = PyIter_Next(iterator)) != NULL) {
|
|
+ signum = PyLong_AsLongAndOverflow(item, &overflow);
|
|
+ Py_DECREF(item);
|
|
+ if (signum <= 0 || signum >= NSIG) {
|
|
+ if (overflow || signum != -1 || !PyErr_Occurred()) {
|
|
+ PyErr_Format(PyExc_ValueError,
|
|
+ "signal number %ld out of range", signum);
|
|
+ }
|
|
+ goto error;
|
|
+ }
|
|
+ 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;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ if (!PyErr_Occurred()) {
|
|
+ Py_DECREF(iterator);
|
|
+ return 1;
|
|
+ }
|
|
+
|
|
+error:
|
|
+ Py_DECREF(iterator);
|
|
+ return 0;
|
|
+}
|
|
+#endif /* HAVE_SIGSET_T */
|
|
+
|
|
#ifdef MS_WINDOWS
|
|
|
|
static int
|
|
diff --git a/Modules/posixmodule.h b/Modules/posixmodule.h
|
|
index 1ec1833..1e00562 100644
|
|
--- a/Modules/posixmodule.h
|
|
+++ b/Modules/posixmodule.h
|
|
@@ -17,8 +17,17 @@ PyAPI_FUNC(PyObject *) _PyLong_FromGid(gid_t);
|
|
PyAPI_FUNC(int) _Py_Uid_Converter(PyObject *, void *);
|
|
PyAPI_FUNC(int) _Py_Gid_Converter(PyObject *, void *);
|
|
#endif /* MS_WINDOWS */
|
|
+
|
|
+#if defined(PYPTHREAD_SIGMASK) || defined(HAVE_SIGWAIT) || \
|
|
+ defined(HAVE_SIGWAITINFO) || defined(HAVE_SIGTIMEDWAIT)
|
|
+# define HAVE_SIGSET_T
|
|
#endif
|
|
|
|
+#ifdef HAVE_SIGSET_T
|
|
+PyAPI_FUNC(int) _Py_Sigset_Converter(PyObject *, void *);
|
|
+#endif /* HAVE_SIGSET_T */
|
|
+#endif /* Py_LIMITED_API */
|
|
+
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c
|
|
index b6b5bf1..0a5f190 100644
|
|
--- a/Modules/signalmodule.c
|
|
+++ b/Modules/signalmodule.c
|
|
@@ -59,6 +59,14 @@ module signal
|
|
[clinic start generated code]*/
|
|
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=b0301a3bde5fe9d3]*/
|
|
|
|
+/*[python input]
|
|
+
|
|
+class sigset_t_converter(CConverter):
|
|
+ type = 'sigset_t'
|
|
+ converter = '_Py_Sigset_Converter'
|
|
+
|
|
+[python start generated code]*/
|
|
+/*[python end generated code: output=da39a3ee5e6b4b0d input=b5689d14466b6823]*/
|
|
|
|
/*
|
|
NOTES ON THE INTERACTION BETWEEN SIGNALS AND THREADS
|
|
@@ -741,69 +749,6 @@ signal_getitimer_impl(PyObject *module, int which)
|
|
|
|
#endif
|
|
|
|
-#if defined(PYPTHREAD_SIGMASK) || defined(HAVE_SIGWAIT) || \
|
|
- defined(HAVE_SIGWAITINFO) || defined(HAVE_SIGTIMEDWAIT)
|
|
-/* Convert an iterable to a sigset.
|
|
- Return 0 on success, return -1 and raise an exception on error. */
|
|
-
|
|
-static int
|
|
-iterable_to_sigset(PyObject *iterable, sigset_t *mask)
|
|
-{
|
|
- int result = -1;
|
|
- PyObject *iterator, *item;
|
|
- long signum;
|
|
-
|
|
- sigemptyset(mask);
|
|
-
|
|
- iterator = PyObject_GetIter(iterable);
|
|
- if (iterator == NULL)
|
|
- goto error;
|
|
-
|
|
- while (1)
|
|
- {
|
|
- item = PyIter_Next(iterator);
|
|
- if (item == NULL) {
|
|
- if (PyErr_Occurred())
|
|
- goto error;
|
|
- else
|
|
- break;
|
|
- }
|
|
-
|
|
- signum = PyLong_AsLong(item);
|
|
- Py_DECREF(item);
|
|
- if (signum == -1 && PyErr_Occurred())
|
|
- goto error;
|
|
- if (0 < signum && signum < NSIG) {
|
|
- 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,
|
|
- "signal number %ld out of range", signum);
|
|
- goto error;
|
|
- }
|
|
- }
|
|
- result = 0;
|
|
-
|
|
-error:
|
|
- Py_XDECREF(iterator);
|
|
- return result;
|
|
-}
|
|
-#endif
|
|
-
|
|
#if defined(PYPTHREAD_SIGMASK) || defined(HAVE_SIGPENDING)
|
|
static PyObject*
|
|
sigset_to_set(sigset_t mask)
|
|
@@ -846,23 +791,20 @@ sigset_to_set(sigset_t mask)
|
|
signal.pthread_sigmask
|
|
|
|
how: int
|
|
- mask: object
|
|
+ mask: sigset_t
|
|
/
|
|
|
|
Fetch and/or change the signal mask of the calling thread.
|
|
[clinic start generated code]*/
|
|
|
|
static PyObject *
|
|
-signal_pthread_sigmask_impl(PyObject *module, int how, PyObject *mask)
|
|
-/*[clinic end generated code: output=ff640fe092bc9181 input=f3b7d7a61b7b8283]*/
|
|
+signal_pthread_sigmask_impl(PyObject *module, int how, sigset_t mask)
|
|
+/*[clinic end generated code: output=0562c0fb192981a8 input=85bcebda442fa77f]*/
|
|
{
|
|
- sigset_t newmask, previous;
|
|
+ sigset_t previous;
|
|
int err;
|
|
|
|
- if (iterable_to_sigset(mask, &newmask))
|
|
- return NULL;
|
|
-
|
|
- err = pthread_sigmask(how, &newmask, &previous);
|
|
+ err = pthread_sigmask(how, &mask, &previous);
|
|
if (err != 0) {
|
|
errno = err;
|
|
PyErr_SetFromErrno(PyExc_OSError);
|
|
@@ -910,7 +852,7 @@ signal_sigpending_impl(PyObject *module)
|
|
/*[clinic input]
|
|
signal.sigwait
|
|
|
|
- sigset: object
|
|
+ sigset: sigset_t
|
|
/
|
|
|
|
Wait for a signal.
|
|
@@ -921,17 +863,13 @@ and returns the signal number.
|
|
[clinic start generated code]*/
|
|
|
|
static PyObject *
|
|
-signal_sigwait(PyObject *module, PyObject *sigset)
|
|
-/*[clinic end generated code: output=557173647424f6e4 input=11af2d82d83c2e94]*/
|
|
+signal_sigwait_impl(PyObject *module, sigset_t sigset)
|
|
+/*[clinic end generated code: output=f43770699d682f96 input=a6fbd47b1086d119]*/
|
|
{
|
|
- sigset_t set;
|
|
int err, signum;
|
|
|
|
- if (iterable_to_sigset(sigset, &set))
|
|
- return NULL;
|
|
-
|
|
Py_BEGIN_ALLOW_THREADS
|
|
- err = sigwait(&set, &signum);
|
|
+ err = sigwait(&sigset, &signum);
|
|
Py_END_ALLOW_THREADS
|
|
if (err) {
|
|
errno = err;
|
|
@@ -1046,7 +984,7 @@ fill_siginfo(siginfo_t *si)
|
|
/*[clinic input]
|
|
signal.sigwaitinfo
|
|
|
|
- sigset: object
|
|
+ sigset: sigset_t
|
|
/
|
|
|
|
Wait synchronously until one of the signals in *sigset* is delivered.
|
|
@@ -1055,20 +993,16 @@ Returns a struct_siginfo containing information about the signal.
|
|
[clinic start generated code]*/
|
|
|
|
static PyObject *
|
|
-signal_sigwaitinfo(PyObject *module, PyObject *sigset)
|
|
-/*[clinic end generated code: output=c40f27b269cd2309 input=f3779a74a991e171]*/
|
|
+signal_sigwaitinfo_impl(PyObject *module, sigset_t sigset)
|
|
+/*[clinic end generated code: output=1eb2f1fa236fdbca input=3d1a7e1f27fc664c]*/
|
|
{
|
|
- sigset_t set;
|
|
siginfo_t si;
|
|
int err;
|
|
int async_err = 0;
|
|
|
|
- if (iterable_to_sigset(sigset, &set))
|
|
- return NULL;
|
|
-
|
|
do {
|
|
Py_BEGIN_ALLOW_THREADS
|
|
- err = sigwaitinfo(&set, &si);
|
|
+ err = sigwaitinfo(&sigset, &si);
|
|
Py_END_ALLOW_THREADS
|
|
} while (err == -1
|
|
&& errno == EINTR && !(async_err = PyErr_CheckSignals()));
|
|
@@ -1085,7 +1019,7 @@ signal_sigwaitinfo(PyObject *module, PyObject *sigset)
|
|
/*[clinic input]
|
|
signal.sigtimedwait
|
|
|
|
- sigset: object
|
|
+ sigset: sigset_t
|
|
timeout as timeout_obj: object
|
|
/
|
|
|
|
@@ -1095,12 +1029,11 @@ The timeout is specified in seconds, with floating point numbers allowed.
|
|
[clinic start generated code]*/
|
|
|
|
static PyObject *
|
|
-signal_sigtimedwait_impl(PyObject *module, PyObject *sigset,
|
|
+signal_sigtimedwait_impl(PyObject *module, sigset_t sigset,
|
|
PyObject *timeout_obj)
|
|
-/*[clinic end generated code: output=f7eff31e679f4312 input=53fd4ea3e3724eb8]*/
|
|
+/*[clinic end generated code: output=59c8971e8ae18a64 input=87fd39237cf0b7ba]*/
|
|
{
|
|
struct timespec ts;
|
|
- sigset_t set;
|
|
siginfo_t si;
|
|
int res;
|
|
_PyTime_t timeout, deadline, monotonic;
|
|
@@ -1114,9 +1047,6 @@ signal_sigtimedwait_impl(PyObject *module, PyObject *sigset,
|
|
return NULL;
|
|
}
|
|
|
|
- if (iterable_to_sigset(sigset, &set))
|
|
- return NULL;
|
|
-
|
|
deadline = _PyTime_GetMonotonicClock() + timeout;
|
|
|
|
do {
|
|
@@ -1124,7 +1054,7 @@ signal_sigtimedwait_impl(PyObject *module, PyObject *sigset,
|
|
return NULL;
|
|
|
|
Py_BEGIN_ALLOW_THREADS
|
|
- res = sigtimedwait(&set, &si, &ts);
|
|
+ res = sigtimedwait(&sigset, &si, &ts);
|
|
Py_END_ALLOW_THREADS
|
|
|
|
if (res != -1)
|
|
--
|
|
2.23.0
|
|
|