[Python-checkins] cpython (3.3): Issue #17097: Make multiprocessing ignore EINTR.

richard.oudkerk python-checkins at python.org
Mon Jul 1 20:12:11 CEST 2013


http://hg.python.org/cpython/rev/3ec5267f51ff
changeset:   84414:3ec5267f51ff
branch:      3.3
parent:      84409:61b6cd7b9819
user:        Richard Oudkerk <shibturn at gmail.com>
date:        Mon Jul 01 18:59:26 2013 +0100
summary:
  Issue #17097: Make multiprocessing ignore EINTR.

files:
  Lib/multiprocessing/connection.py |  18 ++++-
  Lib/test/test_multiprocessing.py  |  70 ++++++++++++++++++-
  Misc/NEWS                         |   2 +
  3 files changed, 86 insertions(+), 4 deletions(-)


diff --git a/Lib/multiprocessing/connection.py b/Lib/multiprocessing/connection.py
--- a/Lib/multiprocessing/connection.py
+++ b/Lib/multiprocessing/connection.py
@@ -366,7 +366,10 @@
     def _send(self, buf, write=_write):
         remaining = len(buf)
         while True:
-            n = write(self._handle, buf)
+            try:
+                n = write(self._handle, buf)
+            except InterruptedError:
+                continue
             remaining -= n
             if remaining == 0:
                 break
@@ -377,7 +380,10 @@
         handle = self._handle
         remaining = size
         while remaining > 0:
-            chunk = read(handle, remaining)
+            try:
+                chunk = read(handle, remaining)
+            except InterruptedError:
+                continue
             n = len(chunk)
             if n == 0:
                 if remaining == size:
@@ -581,7 +587,13 @@
             self._unlink = None
 
     def accept(self):
-        s, self._last_accepted = self._socket.accept()
+        while True:
+            try:
+                s, self._last_accepted = self._socket.accept()
+            except InterruptedError:
+                pass
+            else:
+                break
         s.setblocking(True)
         return Connection(s.detach())
 
diff --git a/Lib/test/test_multiprocessing.py b/Lib/test/test_multiprocessing.py
--- a/Lib/test/test_multiprocessing.py
+++ b/Lib/test/test_multiprocessing.py
@@ -3461,13 +3461,81 @@
         self.assertLessEqual(new_size, old_size)
 
 #
+# Issue #17097: EINTR should be ignored by recv(), send(), accept() etc
+#
+
+class TestIgnoreEINTR(unittest.TestCase):
+
+    @classmethod
+    def _test_ignore(cls, conn):
+        def handler(signum, frame):
+            pass
+        signal.signal(signal.SIGUSR1, handler)
+        conn.send('ready')
+        x = conn.recv()
+        conn.send(x)
+        conn.send_bytes(b'x'*(1024*1024))   # sending 1 MB should block
+
+    @unittest.skipUnless(hasattr(signal, 'SIGUSR1'), 'requires SIGUSR1')
+    def test_ignore(self):
+        conn, child_conn = multiprocessing.Pipe()
+        try:
+            p = multiprocessing.Process(target=self._test_ignore,
+                                        args=(child_conn,))
+            p.daemon = True
+            p.start()
+            child_conn.close()
+            self.assertEqual(conn.recv(), 'ready')
+            time.sleep(0.1)
+            os.kill(p.pid, signal.SIGUSR1)
+            time.sleep(0.1)
+            conn.send(1234)
+            self.assertEqual(conn.recv(), 1234)
+            time.sleep(0.1)
+            os.kill(p.pid, signal.SIGUSR1)
+            self.assertEqual(conn.recv_bytes(), b'x'*(1024*1024))
+            time.sleep(0.1)
+            p.join()
+        finally:
+            conn.close()
+
+    @classmethod
+    def _test_ignore_listener(cls, conn):
+        def handler(signum, frame):
+            pass
+        signal.signal(signal.SIGUSR1, handler)
+        l = multiprocessing.connection.Listener()
+        conn.send(l.address)
+        a = l.accept()
+        a.send('welcome')
+
+    @unittest.skipUnless(hasattr(signal, 'SIGUSR1'), 'requires SIGUSR1')
+    def test_ignore_listener(self):
+        conn, child_conn = multiprocessing.Pipe()
+        try:
+            p = multiprocessing.Process(target=self._test_ignore_listener,
+                                        args=(child_conn,))
+            p.daemon = True
+            p.start()
+            child_conn.close()
+            address = conn.recv()
+            time.sleep(0.1)
+            os.kill(p.pid, signal.SIGUSR1)
+            time.sleep(0.1)
+            client = multiprocessing.connection.Client(address)
+            self.assertEqual(client.recv(), 'welcome')
+            p.join()
+        finally:
+            conn.close()
+
+#
 #
 #
 
 testcases_other = [OtherTest, TestInvalidHandle, TestInitializers,
                    TestStdinBadfiledescriptor, TestWait, TestInvalidFamily,
                    TestFlags, TestTimeouts, TestNoForkBomb,
-                   TestForkAwareThreadLock]
+                   TestForkAwareThreadLock, TestIgnoreEINTR]
 
 #
 #
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -38,6 +38,8 @@
 Library
 -------
 
+- Issue #17097: Make multiprocessing ignore EINTR.
+
 - Issue #18339: Negative ints keys in unpickler.memo dict no longer cause a
   segfault inside the _pickle C extension.
 

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


More information about the Python-checkins mailing list