(original) (raw)
changeset: 85282:4543408e2ba6 parent: 85279:6c9d49b8e3ec parent: 85281:072ba5df77e4 user: Serhiy Storchaka storchaka@gmail.com date: Tue Aug 20 20:50:32 2013 +0300 files: Lib/test/test_poll.py Misc/ACKS Misc/NEWS Modules/selectmodule.c description: Issue #8865: Concurrent invocation of select.poll.poll() now raises a RuntimeError exception. Patch by Christian Schubert. diff -r 6c9d49b8e3ec -r 4543408e2ba6 Lib/test/test_poll.py --- a/Lib/test/test_poll.py Tue Aug 20 20:07:50 2013 +0300 +++ b/Lib/test/test_poll.py Tue Aug 20 20:50:32 2013 +0300 @@ -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 -r 6c9d49b8e3ec -r 4543408e2ba6 Misc/ACKS --- a/Misc/ACKS Tue Aug 20 20:07:50 2013 +0300 +++ b/Misc/ACKS Tue Aug 20 20:50:32 2013 +0300 @@ -1131,6 +1131,7 @@ Scott Schram Robin Schreiber Chad J. Schroeder +Christian Schubert Sam Schulenburg Stefan Schwarzer Dietmar Schwertberger diff -r 6c9d49b8e3ec -r 4543408e2ba6 Misc/NEWS --- a/Misc/NEWS Tue Aug 20 20:07:50 2013 +0300 +++ b/Misc/NEWS Tue Aug 20 20:50:32 2013 +0300 @@ -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 -r 6c9d49b8e3ec -r 4543408e2ba6 Modules/selectmodule.c --- a/Modules/selectmodule.c Tue Aug 20 20:07:50 2013 +0300 +++ b/Modules/selectmodule.c Tue Aug 20 20:50:32 2013 +0300 @@ -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); /storchaka@gmail.com