[Python-checkins] cpython: Issue #8407: signal.pthread_sigmask() returns a set instead of a list

victor.stinner python-checkins at python.org
Wed May 4 13:20:44 CEST 2011


http://hg.python.org/cpython/rev/a5890ff5e3d5
changeset:   69821:a5890ff5e3d5
user:        Victor Stinner <victor.stinner at haypocalc.com>
date:        Wed May 04 13:20:35 2011 +0200
summary:
  Issue #8407: signal.pthread_sigmask() returns a set instead of a list

Update the doc. Refactor also related tests.

files:
  Doc/library/signal.rst  |   7 +-
  Lib/test/test_signal.py |  33 ++++++++------
  Modules/signalmodule.c  |  65 ++++++++++++++++------------
  3 files changed, 59 insertions(+), 46 deletions(-)


diff --git a/Doc/library/signal.rst b/Doc/library/signal.rst
--- a/Doc/library/signal.rst
+++ b/Doc/library/signal.rst
@@ -184,7 +184,7 @@
 
    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.
-   The old signal mask is returned.
+   Return the old signal mask as a set of signals.
 
    The behavior of the call is dependent on the value of *how*, as follows.
 
@@ -196,8 +196,9 @@
     * :data:`SIG_SETMASK`: The set of blocked signals is set to the *mask*
       argument.
 
-   *mask* is a list of signal numbers (e.g. [:const:`signal.SIGINT`,
-   :const:`signal.SIGTERM`]).
+   *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.
diff --git a/Lib/test/test_signal.py b/Lib/test/test_signal.py
--- a/Lib/test/test_signal.py
+++ b/Lib/test/test_signal.py
@@ -486,24 +486,27 @@
 
 @unittest.skipUnless(hasattr(signal, 'pthread_sigmask'),
                      'need signal.pthread_sigmask()')
-class PthreadSigmaskTests(unittest.TestCase):
-    def test_arguments(self):
+class PendingSignalsTests(unittest.TestCase):
+    """
+    Tests for the pthread_sigmask() function.
+    """
+    def handler(self, signum, frame):
+        1/0
+
+    def read_sigmask(self):
+        return signal.pthread_sigmask(signal.SIG_BLOCK, [])
+
+    def test_pthread_sigmask_arguments(self):
         self.assertRaises(TypeError, signal.pthread_sigmask)
         self.assertRaises(TypeError, signal.pthread_sigmask, 1)
         self.assertRaises(TypeError, signal.pthread_sigmask, 1, 2, 3)
         self.assertRaises(RuntimeError, signal.pthread_sigmask, 1700, [])
 
-    def test_block_unlock(self):
+    def test_pthread_sigmask(self):
         import faulthandler
         pid = os.getpid()
         signum = signal.SIGUSR1
 
-        def handler(signum, frame):
-            1/0
-
-        def read_sigmask():
-            return signal.pthread_sigmask(signal.SIG_BLOCK, [])
-
         # The fault handler timeout thread masks all signals. If the main
         # thread masks also SIGUSR1, all threads mask this signal. In this
         # case, if we send SIGUSR1 to the process, the signal is pending in the
@@ -527,7 +530,7 @@
                   "blocked by pthread_sigmask() (issue #11998)")
 
         # Install our signal handler
-        old_handler = signal.signal(signum, handler)
+        old_handler = signal.signal(signum, self.handler)
         self.addCleanup(signal.signal, signum, old_handler)
 
         # Unblock SIGUSR1 (and copy the old mask) to test our signal handler
@@ -543,9 +546,9 @@
             os.kill(pid, signum)
 
         # Check the new mask
-        blocked = read_sigmask()
+        blocked = self.read_sigmask()
         self.assertIn(signum, blocked)
-        self.assertEqual(set(old_mask) ^ set(blocked), {signum})
+        self.assertEqual(old_mask ^ blocked, {signum})
 
         # Unblock SIGUSR1
         if can_test_blocked_signals:
@@ -558,9 +561,9 @@
             os.kill(pid, signum)
 
         # Check the new mask
-        unblocked = read_sigmask()
+        unblocked = self.read_sigmask()
         self.assertNotIn(signum, unblocked)
-        self.assertEqual(set(blocked) ^ set(unblocked), {signum})
+        self.assertEqual(blocked ^ unblocked, {signum})
         self.assertSequenceEqual(old_mask, unblocked)
         # Finally, restore the previous signal handler and the signal mask
 
@@ -570,7 +573,7 @@
         support.run_unittest(BasicSignalTests, InterProcessSignalTests,
                              WakeupSignalTests, SiginterruptTest,
                              ItimerTest, WindowsSignalTests,
-                             PthreadSigmaskTests)
+                             PendingSignalsTests)
     finally:
         support.reap_children()
 
diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c
--- a/Modules/signalmodule.c
+++ b/Modules/signalmodule.c
@@ -552,11 +552,45 @@
     return result;
 }
 
+static PyObject*
+sigset_to_set(sigset_t mask)
+{
+    PyObject *signum, *result;
+    int sig;
+
+    result = PySet_New(0);
+    if (result == NULL)
+        return NULL;
+
+    for (sig = 1; sig < NSIG; sig++) {
+        if (sigismember(&mask, sig) != 1)
+            continue;
+
+        /* Handle the case where it is a member by adding the signal to
+           the result list.  Ignore the other cases because they mean the
+           signal isn't a member of the mask or the signal was invalid,
+           and an invalid signal must have been our fault in constructing
+           the loop boundaries. */
+        signum = PyLong_FromLong(sig);
+        if (signum == NULL) {
+            Py_DECREF(result);
+            return NULL;
+        }
+        if (PySet_Add(result, signum) == -1) {
+            Py_DECREF(signum);
+            Py_DECREF(result);
+            return NULL;
+        }
+        Py_DECREF(signum);
+    }
+    return result;
+}
+
 static PyObject *
 signal_pthread_sigmask(PyObject *self, PyObject *args)
 {
-    int how, sig;
-    PyObject *signals, *result, *signum;
+    int how;
+    PyObject *signals;
     sigset_t mask, previous;
     int err;
 
@@ -577,32 +611,7 @@
     if (PyErr_CheckSignals())
         return NULL;
 
-    result = PyList_New(0);
-    if (result == NULL)
-        return NULL;
-
-    for (sig = 1; sig < NSIG; sig++) {
-        if (sigismember(&previous, sig) != 1)
-            continue;
-
-        /* Handle the case where it is a member by adding the signal to
-           the result list.  Ignore the other cases because they mean the
-           signal isn't a member of the mask or the signal was invalid,
-           and an invalid signal must have been our fault in constructing
-           the loop boundaries. */
-        signum = PyLong_FromLong(sig);
-        if (signum == NULL) {
-            Py_DECREF(result);
-            return NULL;
-        }
-        if (PyList_Append(result, signum) == -1) {
-            Py_DECREF(signum);
-            Py_DECREF(result);
-            return NULL;
-        }
-        Py_DECREF(signum);
-    }
-    return result;
+    return sigset_to_set(previous);
 }
 
 PyDoc_STRVAR(signal_pthread_sigmask_doc,

-- 
Repository URL: http://hg.python.org/cpython


More information about the Python-checkins mailing list