mirror of
https://github.com/python/cpython.git
synced 2025-11-01 18:51:43 +00:00
Issue #8865: Concurrent invocation of select.poll.poll() now raises a
RuntimeError exception. Patch by Christian Schubert.
This commit is contained in:
parent
ec67d187ee
commit
b1973c252c
4 changed files with 57 additions and 2 deletions
|
|
@ -1,8 +1,16 @@
|
||||||
# Test case for the os.poll() function
|
# Test case for the os.poll() function
|
||||||
|
|
||||||
import os, select, random, unittest
|
import os
|
||||||
|
import random
|
||||||
|
import select
|
||||||
import _testcapi
|
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:
|
try:
|
||||||
select.poll
|
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.INT_MAX + 1)
|
||||||
self.assertRaises(OverflowError, pollster.poll, _testcapi.UINT_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():
|
def test_main():
|
||||||
run_unittest(PollTests)
|
run_unittest(PollTests)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1097,6 +1097,7 @@ Arvin Schnell
|
||||||
Scott Schram
|
Scott Schram
|
||||||
Robin Schreiber
|
Robin Schreiber
|
||||||
Chad J. Schroeder
|
Chad J. Schroeder
|
||||||
|
Christian Schubert
|
||||||
Sam Schulenburg
|
Sam Schulenburg
|
||||||
Stefan Schwarzer
|
Stefan Schwarzer
|
||||||
Dietmar Schwertberger
|
Dietmar Schwertberger
|
||||||
|
|
|
||||||
|
|
@ -66,6 +66,9 @@ Core and Builtins
|
||||||
Library
|
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
|
- Issue #13461: Fix a crash in the TextIOWrapper.tell method on 64-bit
|
||||||
platforms. Patch by Yogesh Chaudhari.
|
platforms. Patch by Yogesh Chaudhari.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -332,6 +332,7 @@ typedef struct {
|
||||||
int ufd_uptodate;
|
int ufd_uptodate;
|
||||||
int ufd_len;
|
int ufd_len;
|
||||||
struct pollfd *ufds;
|
struct pollfd *ufds;
|
||||||
|
int poll_running;
|
||||||
} pollObject;
|
} pollObject;
|
||||||
|
|
||||||
static PyTypeObject poll_Type;
|
static PyTypeObject poll_Type;
|
||||||
|
|
@ -528,16 +529,27 @@ poll_poll(pollObject *self, PyObject *args)
|
||||||
return NULL;
|
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 */
|
/* Ensure the ufd array is up to date */
|
||||||
if (!self->ufd_uptodate)
|
if (!self->ufd_uptodate)
|
||||||
if (update_ufd_array(self) == 0)
|
if (update_ufd_array(self) == 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
self->poll_running = 1;
|
||||||
|
|
||||||
/* call poll() */
|
/* call poll() */
|
||||||
Py_BEGIN_ALLOW_THREADS
|
Py_BEGIN_ALLOW_THREADS
|
||||||
poll_result = poll(self->ufds, self->ufd_len, timeout);
|
poll_result = poll(self->ufds, self->ufd_len, timeout);
|
||||||
Py_END_ALLOW_THREADS
|
Py_END_ALLOW_THREADS
|
||||||
|
|
||||||
|
self->poll_running = 0;
|
||||||
|
|
||||||
if (poll_result < 0) {
|
if (poll_result < 0) {
|
||||||
PyErr_SetFromErrno(PyExc_OSError);
|
PyErr_SetFromErrno(PyExc_OSError);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
@ -614,6 +626,7 @@ newPollObject(void)
|
||||||
array pointed to by ufds matches the contents of the dictionary. */
|
array pointed to by ufds matches the contents of the dictionary. */
|
||||||
self->ufd_uptodate = 0;
|
self->ufd_uptodate = 0;
|
||||||
self->ufds = NULL;
|
self->ufds = NULL;
|
||||||
|
self->poll_running = 0;
|
||||||
self->dict = PyDict_New();
|
self->dict = PyDict_New();
|
||||||
if (self->dict == NULL) {
|
if (self->dict == NULL) {
|
||||||
Py_DECREF(self);
|
Py_DECREF(self);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue