Skip to content

Commit

Permalink
Handle EINTR from poll with zero timeout (#1399)
Browse files Browse the repository at this point in the history
Closes #1396
  • Loading branch information
bmerry authored and SethMichaelLarson committed Jun 22, 2018
1 parent 6be6372 commit 0f85e05
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 4 deletions.
3 changes: 3 additions & 0 deletions CONTRIBUTORS.txt
Original file line number Diff line number Diff line change
Expand Up @@ -259,5 +259,8 @@ In chronological order:
* Improve contribution guide
* Add ``HTTPResponse.geturl`` method to provide ``urllib2.urlopen().geturl()`` behavior

* Bruce Merry <http://www.brucemerry.org.za>
* Fix leaking exceptions when system calls are interrupted with zero timeout

* [Your name or handle] <[email or website]>
* [Brief summary of your changes]
34 changes: 34 additions & 0 deletions test/test_wait.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,40 @@ def handler(sig, frame):
assert interrupt_count[0] > 0


@pytest.mark.skipif(
not hasattr(signal, "setitimer"),
reason="need setitimer() support"
)
@pytest.mark.parametrize("wfs", variants)
def test_eintr_zero_timeout(wfs, spair):
a, b = spair
interrupt_count = [0]

def handler(sig, frame):
assert sig == signal.SIGALRM
interrupt_count[0] += 1

old_handler = signal.signal(signal.SIGALRM, handler)
try:
assert not wfs(a, read=True, timeout=0)
try:
# Start delivering SIGALRM 1000 times per second,
# to trigger race conditions such as
# https://github.com/urllib3/urllib3/issues/1396.
signal.setitimer(signal.ITIMER_REAL, 0.001, 0.001)
# Hammer the system call for a while to trigger the
# race.
for i in range(100000):
wfs(a, read=True, timeout=0)
finally:
# Stop delivering SIGALRM
signal.setitimer(signal.ITIMER_REAL, 0)
finally:
signal.signal(signal.SIGALRM, old_handler)

assert interrupt_count[0] > 0


@pytest.mark.skipif(
not hasattr(signal, "setitimer"),
reason="need setitimer() support"
Expand Down
5 changes: 1 addition & 4 deletions urllib3/util/wait.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,6 @@ def _retry_on_intr(fn, timeout):
else:
# Old and broken Pythons.
def _retry_on_intr(fn, timeout):
if timeout is not None and timeout <= 0:
return fn(timeout)

if timeout is None:
deadline = float("inf")
else:
Expand Down Expand Up @@ -117,7 +114,7 @@ def _have_working_poll():
# from libraries like eventlet/greenlet.
try:
poll_obj = select.poll()
poll_obj.poll(0)
_retry_on_intr(poll_obj.poll, 0)
except (AttributeError, OSError):
return False
else:
Expand Down

0 comments on commit 0f85e05

Please sign in to comment.