[Python-checkins] cpython (merge 3.3 -> default): Issue #8865: Concurrent invocation of select.poll.poll() now raises a

serhiy.storchaka python-checkins at python.org
Tue Aug 20 19:59:36 CEST 2013


http://hg.python.org/cpython/rev/4543408e2ba6
changeset:   85282:4543408e2ba6
parent:      85279:6c9d49b8e3ec
parent:      85281:072ba5df77e4
user:        Serhiy Storchaka <storchaka at gmail.com>
date:        Tue Aug 20 20:50:32 2013 +0300
summary:
  Issue #8865: Concurrent invocation of select.poll.poll() now raises a
RuntimeError exception.  Patch by Christian Schubert.

files:
  Lib/test/test_poll.py  |  42 ++++++++++++++++++++++++++++-
  Misc/ACKS              |   1 +
  Misc/NEWS              |   3 ++
  Modules/selectmodule.c |  13 +++++++++
  4 files changed, 57 insertions(+), 2 deletions(-)


diff --git a/Lib/test/test_poll.py b/Lib/test/test_poll.py
--- a/Lib/test/test_poll.py
+++ b/Lib/test/test_poll.py
@@ -1,8 +1,16 @@
 # Test case for the os.poll() function
 
-import os, select, random, unittest, subprocess
+import os
+import random
+import select
 import _testcapi
-from test.support import TESTFN, run_unittest
+try:
+    import threading
+except ImportError:
+    threading = None
+import time
+import unittest
+from test.support import TESTFN, run_unittest, reap_threads
 
 try:
     select.poll
@@ -161,6 +169,36 @@
         self.assertRaises(OverflowError, pollster.poll, _testcapi.INT_MAX + 1)
         self.assertRaises(OverflowError, pollster.poll, _testcapi.UINT_MAX + 1)
 
+    @unittest.skipUnless(threading, 'Threading required for this test.')
+    @reap_threads
+    def test_threaded_poll(self):
+        r, w = os.pipe()
+        self.addCleanup(os.close, r)
+        self.addCleanup(os.close, w)
+        rfds = []
+        for i in range(10):
+            fd = os.dup(r)
+            self.addCleanup(os.close, fd)
+            rfds.append(fd)
+        pollster = select.poll()
+        for fd in rfds:
+            pollster.register(fd, select.POLLIN)
+
+        t = threading.Thread(target=pollster.poll)
+        t.start()
+        try:
+            time.sleep(0.5)
+            # trigger ufds array reallocation
+            for fd in rfds:
+                pollster.unregister(fd)
+            pollster.register(w, select.POLLOUT)
+            self.assertRaises(RuntimeError, pollster.poll)
+        finally:
+            # and make the call to poll() from the thread return
+            os.write(w, b'spam')
+            t.join()
+
+
 def test_main():
     run_unittest(PollTests)
 
diff --git a/Misc/ACKS b/Misc/ACKS
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -1131,6 +1131,7 @@
 Scott Schram
 Robin Schreiber
 Chad J. Schroeder
+Christian Schubert
 Sam Schulenburg
 Stefan Schwarzer
 Dietmar Schwertberger
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -38,6 +38,9 @@
 Library
 -------
 
+- Issue #8865: Concurrent invocation of select.poll.poll() now raises a
+  RuntimeError exception.  Patch by Christian Schubert.
+
 - Issue #18777: The ssl module now uses the new CRYPTO_THREADID API of
   OpenSSL 1.0.0+ instead of the deprecated CRYPTO id callback function.
 
diff --git a/Modules/selectmodule.c b/Modules/selectmodule.c
--- a/Modules/selectmodule.c
+++ b/Modules/selectmodule.c
@@ -327,6 +327,7 @@
     int ufd_uptodate;
     int ufd_len;
     struct pollfd *ufds;
+    int poll_running;
 } pollObject;
 
 static PyTypeObject poll_Type;
@@ -523,16 +524,27 @@
             return NULL;
     }
 
+    /* Avoid concurrent poll() invocation, issue 8865 */
+    if (self->poll_running) {
+        PyErr_SetString(PyExc_RuntimeError,
+                        "concurrent poll() invocation");
+        return NULL;
+    }
+
     /* Ensure the ufd array is up to date */
     if (!self->ufd_uptodate)
         if (update_ufd_array(self) == 0)
             return NULL;
 
+    self->poll_running = 1;
+
     /* call poll() */
     Py_BEGIN_ALLOW_THREADS
     poll_result = poll(self->ufds, self->ufd_len, timeout);
     Py_END_ALLOW_THREADS
 
+    self->poll_running = 0;
+
     if (poll_result < 0) {
         PyErr_SetFromErrno(PyExc_OSError);
         return NULL;
@@ -609,6 +621,7 @@
        array pointed to by ufds matches the contents of the dictionary. */
     self->ufd_uptodate = 0;
     self->ufds = NULL;
+    self->poll_running = 0;
     self->dict = PyDict_New();
     if (self->dict == NULL) {
         Py_DECREF(self);

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


More information about the Python-checkins mailing list