Issue #8865: Concurrent invocation of select.poll.poll() now raises a

RuntimeError exception.  Patch by Christian Schubert.
This commit is contained in:
Serhiy Storchaka 2013-08-20 20:38:21 +03:00
parent ec67d187ee
commit b1973c252c
4 changed files with 57 additions and 2 deletions

View File

@ -1,8 +1,16 @@
# Test case for the os.poll() function
import os, select, random, unittest
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
@ -160,6 +168,36 @@ class PollTests(unittest.TestCase):
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)

View File

@ -1097,6 +1097,7 @@ Arvin Schnell
Scott Schram
Robin Schreiber
Chad J. Schroeder
Christian Schubert
Sam Schulenburg
Stefan Schwarzer
Dietmar Schwertberger

View File

@ -66,6 +66,9 @@ Core and Builtins
Library
-------
- Issue #8865: Concurrent invocation of select.poll.poll() now raises a
RuntimeError exception. Patch by Christian Schubert.
- Issue #13461: Fix a crash in the TextIOWrapper.tell method on 64-bit
platforms. Patch by Yogesh Chaudhari.

View File

@ -332,6 +332,7 @@ typedef struct {
int ufd_uptodate;
int ufd_len;
struct pollfd *ufds;
int poll_running;
} pollObject;
static PyTypeObject poll_Type;
@ -528,16 +529,27 @@ poll_poll(pollObject *self, PyObject *args)
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;
@ -614,6 +626,7 @@ newPollObject(void)
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);