Add support for the itimer module with blocking detection
This will allow for subsecond blocking detection thanks to the itimer module recently released by Slide, Inc: http://github.com/slideinc/itimer
This commit is contained in:
@@ -132,13 +132,14 @@ def tpool_exceptions(state = False):
|
|||||||
from eventlet import tpool
|
from eventlet import tpool
|
||||||
tpool.QUIET = not state
|
tpool.QUIET = not state
|
||||||
|
|
||||||
def hub_blocking_detection(state = False):
|
def hub_blocking_detection(state = False, resolution = 1):
|
||||||
"""Toggles whether Eventlet makes an effort to detect blocking
|
"""Toggles whether Eventlet makes an effort to detect blocking
|
||||||
behavior in other code. It does this by setting a SIGALARM with a short
|
behavior in other code. It does this by setting a SIGALARM with a short
|
||||||
timeout.
|
timeout.
|
||||||
"""
|
"""
|
||||||
from eventlet import hubs
|
from eventlet import hubs
|
||||||
hubs.get_hub().debug_blocking = state
|
hubs.get_hub().debug_blocking = state
|
||||||
|
hubs.get_hub().debug_blocking_resolution = resolution
|
||||||
if(not state):
|
if(not state):
|
||||||
hubs.get_hub().block_detect_post()
|
hubs.get_hub().block_detect_post()
|
||||||
|
|
||||||
|
@@ -4,6 +4,13 @@ import traceback
|
|||||||
import warnings
|
import warnings
|
||||||
import signal
|
import signal
|
||||||
|
|
||||||
|
HAS_ITIMER = False
|
||||||
|
try:
|
||||||
|
import itimer
|
||||||
|
HAS_ITIMER = True
|
||||||
|
except ImportError:
|
||||||
|
pass
|
||||||
|
|
||||||
from eventlet.support import greenlets as greenlet, clear_sys_exc_info
|
from eventlet.support import greenlets as greenlet, clear_sys_exc_info
|
||||||
from eventlet.hubs import timer
|
from eventlet.hubs import timer
|
||||||
from eventlet import patcher
|
from eventlet import patcher
|
||||||
@@ -71,13 +78,19 @@ class BaseHub(object):
|
|||||||
self.timers_canceled = 0
|
self.timers_canceled = 0
|
||||||
self.debug_exceptions = True
|
self.debug_exceptions = True
|
||||||
self.debug_blocking = False
|
self.debug_blocking = False
|
||||||
|
self.debug_blocking_resolution = 1
|
||||||
|
|
||||||
def block_detect_pre(self):
|
def block_detect_pre(self):
|
||||||
# shortest alarm we can possibly raise is one second
|
# shortest alarm we can possibly raise is one second
|
||||||
tmp = signal.signal(signal.SIGALRM, alarm_handler)
|
tmp = signal.signal(signal.SIGALRM, alarm_handler)
|
||||||
if tmp != alarm_handler:
|
if tmp != alarm_handler:
|
||||||
self._old_signal_handler = tmp
|
self._old_signal_handler = tmp
|
||||||
signal.alarm(1)
|
|
||||||
|
if HAS_ITIMER:
|
||||||
|
itimer.alarm(self.debug_blocking_resolution)
|
||||||
|
else:
|
||||||
|
signal.alarm(self.debug_blocking_resolution)
|
||||||
|
|
||||||
def block_detect_post(self):
|
def block_detect_post(self):
|
||||||
if (hasattr(self, "_old_signal_handler") and
|
if (hasattr(self, "_old_signal_handler") and
|
||||||
self._old_signal_handler):
|
self._old_signal_handler):
|
||||||
|
@@ -92,6 +92,16 @@ def skip_on_windows(func):
|
|||||||
import sys
|
import sys
|
||||||
return skip_if(sys.platform.startswith('win'))(func)
|
return skip_if(sys.platform.startswith('win'))(func)
|
||||||
|
|
||||||
|
def skip_if_no_itimer(func):
|
||||||
|
""" Decorator that skips a test if the `itimer` module isn't found """
|
||||||
|
has_itimer = False
|
||||||
|
try:
|
||||||
|
import itimer
|
||||||
|
has_itimer = True
|
||||||
|
except ImportError:
|
||||||
|
pass
|
||||||
|
return skip_unless(has_itimer)(func)
|
||||||
|
|
||||||
|
|
||||||
class TestIsTakingTooLong(Exception):
|
class TestIsTakingTooLong(Exception):
|
||||||
""" Custom exception class to be raised when a test's runtime exceeds a limit. """
|
""" Custom exception class to be raised when a test's runtime exceeds a limit. """
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
from tests import LimitedTestCase, main, skip_with_pyevent
|
from tests import LimitedTestCase, main, skip_with_pyevent, skip_if_no_itimer
|
||||||
import time
|
import time
|
||||||
import eventlet
|
import eventlet
|
||||||
from eventlet import hubs
|
from eventlet import hubs
|
||||||
@@ -154,6 +154,18 @@ class TestHubBlockingDetector(LimitedTestCase):
|
|||||||
self.assertRaises(RuntimeError, gt.wait)
|
self.assertRaises(RuntimeError, gt.wait)
|
||||||
debug.hub_blocking_detection(False)
|
debug.hub_blocking_detection(False)
|
||||||
|
|
||||||
|
@skip_if_no_itimer
|
||||||
|
def test_block_detect_with_itimer(self):
|
||||||
|
def look_im_blocking():
|
||||||
|
import time
|
||||||
|
time.sleep(0.5)
|
||||||
|
|
||||||
|
from eventlet import debug
|
||||||
|
debug.hub_blocking_detection(True, resolution=0.1)
|
||||||
|
gt = eventlet.spawn(look_im_blocking)
|
||||||
|
self.assertRaises(RuntimeError, gt.wait)
|
||||||
|
debug.hub_blocking_detection(False)
|
||||||
|
|
||||||
class TestSuspend(LimitedTestCase):
|
class TestSuspend(LimitedTestCase):
|
||||||
TEST_TIMEOUT=3
|
TEST_TIMEOUT=3
|
||||||
def test_suspend_doesnt_crash(self):
|
def test_suspend_doesnt_crash(self):
|
||||||
|
Reference in New Issue
Block a user