Issue #23485: Enhance and update selectors doc and test_selectors
Selector.select() is now retried with the recomputed timeout when interrupted by a signal. Write an unit test with a signal handler raising an exception, and a unit with a signal handler which does not raise an exception (it does nothing).
This commit is contained in:
parent
45ca48b03d
commit
b310173319
|
@ -159,6 +159,12 @@ below:
|
||||||
timeout has elapsed if the current process receives a signal: in this
|
timeout has elapsed if the current process receives a signal: in this
|
||||||
case, an empty list will be returned.
|
case, an empty list will be returned.
|
||||||
|
|
||||||
|
.. versionchanged:: 3.5
|
||||||
|
The selector is now retried with a recomputed timeout when interrupted
|
||||||
|
by a signal if the signal handler did not raise an exception (see
|
||||||
|
:pep:`475` for the rationale), instead of returning an empty list
|
||||||
|
of events before the timeout.
|
||||||
|
|
||||||
.. method:: close()
|
.. method:: close()
|
||||||
|
|
||||||
Close the selector.
|
Close the selector.
|
||||||
|
|
|
@ -357,7 +357,35 @@ class BaseSelectorTestCase(unittest.TestCase):
|
||||||
|
|
||||||
@unittest.skipUnless(hasattr(signal, "alarm"),
|
@unittest.skipUnless(hasattr(signal, "alarm"),
|
||||||
"signal.alarm() required for this test")
|
"signal.alarm() required for this test")
|
||||||
def test_select_interrupt(self):
|
def test_select_interrupt_exc(self):
|
||||||
|
s = self.SELECTOR()
|
||||||
|
self.addCleanup(s.close)
|
||||||
|
|
||||||
|
rd, wr = self.make_socketpair()
|
||||||
|
|
||||||
|
class InterruptSelect(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def handler(*args):
|
||||||
|
raise InterruptSelect
|
||||||
|
|
||||||
|
orig_alrm_handler = signal.signal(signal.SIGALRM, handler)
|
||||||
|
self.addCleanup(signal.signal, signal.SIGALRM, orig_alrm_handler)
|
||||||
|
self.addCleanup(signal.alarm, 0)
|
||||||
|
|
||||||
|
signal.alarm(1)
|
||||||
|
|
||||||
|
s.register(rd, selectors.EVENT_READ)
|
||||||
|
t = time()
|
||||||
|
# select() is interrupted by a signal which raises an exception
|
||||||
|
with self.assertRaises(InterruptSelect):
|
||||||
|
s.select(30)
|
||||||
|
# select() was interrupted before the timeout of 30 seconds
|
||||||
|
self.assertLess(time() - t, 5.0)
|
||||||
|
|
||||||
|
@unittest.skipUnless(hasattr(signal, "alarm"),
|
||||||
|
"signal.alarm() required for this test")
|
||||||
|
def test_select_interrupt_noraise(self):
|
||||||
s = self.SELECTOR()
|
s = self.SELECTOR()
|
||||||
self.addCleanup(s.close)
|
self.addCleanup(s.close)
|
||||||
|
|
||||||
|
@ -371,8 +399,11 @@ class BaseSelectorTestCase(unittest.TestCase):
|
||||||
|
|
||||||
s.register(rd, selectors.EVENT_READ)
|
s.register(rd, selectors.EVENT_READ)
|
||||||
t = time()
|
t = time()
|
||||||
self.assertFalse(s.select(2))
|
# select() is interrupted by a signal, but the signal handler doesn't
|
||||||
self.assertLess(time() - t, 2.5)
|
# raise an exception, so select() should by retries with a recomputed
|
||||||
|
# timeout
|
||||||
|
self.assertFalse(s.select(1.5))
|
||||||
|
self.assertGreaterEqual(time() - t, 1.0)
|
||||||
|
|
||||||
|
|
||||||
class ScalableSelectorMixIn:
|
class ScalableSelectorMixIn:
|
||||||
|
|
Loading…
Reference in New Issue