Commit ea2e65de authored by Jason Madden's avatar Jason Madden

sleep(0) can take a long time on Windows.

Fixes #1314
parent ef464f1e
......@@ -55,6 +55,9 @@
- Make gevent's pywsgi server set the non-standard environment value
``wsgi.input_terminated`` to True. See :issue:`1308`.
- Make `gevent.util.assert_switches` produce more informative messages
when the assertion fails.
1.3.7 (2018-10-12)
==================
......
......@@ -10,11 +10,8 @@ environment:
# Pre-installed Python versions, which Appveyor may upgrade to
# a later point release.
- PYTHON: "C:\\pypy2-v6.0.0-win32"
PYTHON_ID: "pypy"
PYTHON_EXE: pypy
PYTHON_VERSION: "2.7.x"
PYTHON_ARCH: "32"
# 64-bit
- PYTHON: "C:\\Python37-x64"
PYTHON_VERSION: "3.7.x"
......@@ -31,47 +28,55 @@ environment:
PYTHON_ARCH: "64"
PYTHON_EXE: python
- PYTHON: "C:\\Python34-x64"
PYTHON_VERSION: "3.4.x" # currently 3.4.4
- PYTHON: "C:\\Python35-x64"
PYTHON_VERSION: "3.5.x" # currently 3.5.2
PYTHON_ARCH: "64"
PYTHON_EXE: python
- PYTHON: "C:\\Python35-x64"
PYTHON_VERSION: "3.5.x" # currently 3.5.2
- PYTHON: "C:\\Python34-x64"
PYTHON_VERSION: "3.4.x" # currently 3.4.4
PYTHON_ARCH: "64"
PYTHON_EXE: python
- PYTHON: "C:\\Python35"
PYTHON_VERSION: "3.5.x" # currently 3.5.2
# 32-bit
- PYTHON: "C:\\pypy2-v6.0.0-win32"
PYTHON_ID: "pypy"
PYTHON_EXE: pypy
PYTHON_VERSION: "2.7.x"
PYTHON_ARCH: "32"
# 32-bit, wheel only (no testing)
- PYTHON: "C:\\Python37"
PYTHON_VERSION: "3.7.x"
PYTHON_ARCH: "32"
PYTHON_EXE: python
GWHEEL_ONLY: true
- PYTHON: "C:\\Python27"
PYTHON_VERSION: "2.7.x" # currently 2.7.13
- PYTHON: "C:\\Python36"
PYTHON_VERSION: "3.6.x" # currently 3.6.3
PYTHON_ARCH: "32"
PYTHON_EXE: python
GWHEEL_ONLY: true
- PYTHON: "C:\\Python34"
PYTHON_VERSION: "3.4.x" # currently 3.4.3
- PYTHON: "C:\\Python35"
PYTHON_VERSION: "3.5.x" # currently 3.5.2
PYTHON_ARCH: "32"
PYTHON_EXE: python
GWHEEL_ONLY: true
- PYTHON: "C:\\Python36"
PYTHON_VERSION: "3.6.x" # currently 3.6.3
- PYTHON: "C:\\Python34"
PYTHON_VERSION: "3.4.x" # currently 3.4.3
PYTHON_ARCH: "32"
PYTHON_EXE: python
GWHEEL_ONLY: true
- PYTHON: "C:\\Python37"
PYTHON_VERSION: "3.7.x"
- PYTHON: "C:\\Python27"
PYTHON_VERSION: "2.7.x" # currently 2.7.13
PYTHON_ARCH: "32"
PYTHON_EXE: python
GWHEEL_ONLY: true
# Also test a Python version not pre-installed
# See: https://github.com/ogrisel/python-appveyor-demo/issues/10
......
......@@ -221,23 +221,37 @@ class TestAssertSwitches(unittest.TestCase):
def test_time_sleep(self):
# A real blocking function
from time import sleep
with self.assertRaises(util._FailedToSwitch):
# No time given, we detect the failure to switch immediately
with self.assertRaises(util._FailedToSwitch) as exc:
with util.assert_switches():
sleep(0.001)
# Supply a max allowed and exceed it
message = str(exc.exception)
self.assertIn('To any greenlet in', message)
# Supply a max blocking allowed and exceed it
with self.assertRaises(util._FailedToSwitch):
with util.assert_switches(0.001):
sleep(0.1)
# Stay within it, but don't switch to the hub
with self.assertRaises(util._FailedToSwitch):
# Supply a max blocking allowed, and exit before that happens,
# but don't switch to the hub as requested
with self.assertRaises(util._FailedToSwitch) as exc:
with util.assert_switches(0.001, hub_only=True):
sleep(0)
# Stay within it, and we only watch for any switch
with util.assert_switches(0.001, hub_only=False):
message = str(exc.exception)
self.assertIn('To the hub in', message)
self.assertIn('(max allowed 0.0010 seconds)', message)
# Supply a max blocking allowed, and exit before that happens,
# and allow any switch (or no switch).
# Note that we need to use a relatively long duration;
# sleep(0) on Windows can actually take a substantial amount of time
# sometimes (more than 0.001s)
with util.assert_switches(1.0, hub_only=False):
sleep(0)
......
......@@ -12,6 +12,7 @@ import traceback
from greenlet import getcurrent
from gevent._compat import perf_counter
from gevent._compat import PYPY
from gevent._compat import thread_mod_name
from gevent._util import _NONE
......@@ -541,10 +542,15 @@ class assert_switches(object):
pass
.. versionadded:: 1.3
.. versionchanged:: 1.4
If an exception is raised, it now includes information about
the duration of blocking and the parameters of this object.
"""
hub = None
tracer = None
_entered = None
def __init__(self, max_blocking_time=None, hub_only=False):
......@@ -567,6 +573,7 @@ class assert_switches(object):
else:
self.tracer = _tracer.MaxSwitchTracer(hub, self.max_blocking_time)
self._entered = perf_counter()
self.tracer.monitor_current_greenlet_blocking()
return self
......@@ -583,6 +590,14 @@ class assert_switches(object):
did_block = tracer.did_block_hub(hub)
if did_block:
execution_time_s = perf_counter() - self._entered
active_greenlet = did_block[1]
report_lines = tracer.did_block_hub_report(hub, active_greenlet, {})
raise _FailedToSwitch('\n'.join(report_lines))
message = 'To the hub' if self.hub_only else 'To any greenlet'
message += ' in %.4f seconds' % (execution_time_s,)
max_block = self.max_blocking_time
message += ' (max allowed %.4f seconds)' % (max_block,) if max_block else ''
message += '\n'
message += '\n'.join(report_lines)
raise _FailedToSwitch(message)
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment