Probably horribly broken block detecter, only for poll/epoll hubs.
This commit is contained in:
@@ -130,3 +130,14 @@ def tpool_exceptions(state = False):
|
|||||||
it normally does."""
|
it normally does."""
|
||||||
from eventlet import tpool
|
from eventlet import tpool
|
||||||
tpool.QUIET = not state
|
tpool.QUIET = not state
|
||||||
|
|
||||||
|
def hub_blocking_detection(state = False):
|
||||||
|
"""Toggles whether Eventlet makes an effort to detect blocking
|
||||||
|
behavior in other code. It does this by setting a SIGALARM with a short
|
||||||
|
timeout.
|
||||||
|
"""
|
||||||
|
from eventlet import hubs
|
||||||
|
hubs.get_hub().debug_blocking = state
|
||||||
|
if(not state):
|
||||||
|
hubs.get_hub().block_detect_post()
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import heapq
|
|||||||
import sys
|
import sys
|
||||||
import traceback
|
import traceback
|
||||||
import warnings
|
import warnings
|
||||||
|
import signal
|
||||||
|
|
||||||
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
|
||||||
@@ -42,6 +43,11 @@ class DebugListener(FdListener):
|
|||||||
__str__ = __repr__
|
__str__ = __repr__
|
||||||
|
|
||||||
|
|
||||||
|
def alarm_handler(signum, frame):
|
||||||
|
import inspect
|
||||||
|
raise RuntimeError("ALARMED at" + str(inspect.getframeinfo(frame)))
|
||||||
|
|
||||||
|
|
||||||
class BaseHub(object):
|
class BaseHub(object):
|
||||||
""" Base hub class for easing the implementation of subclasses that are
|
""" Base hub class for easing the implementation of subclasses that are
|
||||||
specific to a particular underlying event architecture. """
|
specific to a particular underlying event architecture. """
|
||||||
@@ -62,8 +68,21 @@ class BaseHub(object):
|
|||||||
self.timers = []
|
self.timers = []
|
||||||
self.next_timers = []
|
self.next_timers = []
|
||||||
self.lclass = FdListener
|
self.lclass = FdListener
|
||||||
self.debug_exceptions = True
|
|
||||||
self.timers_canceled = 0
|
self.timers_canceled = 0
|
||||||
|
self.debug_exceptions = True
|
||||||
|
self.debug_blocking = False
|
||||||
|
|
||||||
|
def block_detect_pre(self):
|
||||||
|
# shortest alarm we can possibly raise is one second
|
||||||
|
tmp = signal.signal(signal.SIGALRM, alarm_handler)
|
||||||
|
if tmp != alarm_handler:
|
||||||
|
self._old_signal_handler = tmp
|
||||||
|
signal.alarm(1)
|
||||||
|
def block_detect_post(self):
|
||||||
|
if (hasattr(self, "_old_signal_handler") and
|
||||||
|
self._old_signal_handler):
|
||||||
|
signal.signal(signal.SIGALRM, self._old_signal_handler)
|
||||||
|
signal.alarm(0)
|
||||||
|
|
||||||
def add(self, evtype, fileno, cb):
|
def add(self, evtype, fileno, cb):
|
||||||
""" Signals an intent to or write a particular file descriptor.
|
""" Signals an intent to or write a particular file descriptor.
|
||||||
@@ -166,7 +185,11 @@ class BaseHub(object):
|
|||||||
self.stopping = False
|
self.stopping = False
|
||||||
while not self.stopping:
|
while not self.stopping:
|
||||||
self.prepare_timers()
|
self.prepare_timers()
|
||||||
|
if self.debug_blocking:
|
||||||
|
self.block_detect_pre()
|
||||||
self.fire_timers(self.clock())
|
self.fire_timers(self.clock())
|
||||||
|
if self.debug_blocking:
|
||||||
|
self.block_detect_post()
|
||||||
self.prepare_timers()
|
self.prepare_timers()
|
||||||
wakeup_when = self.sleep_until()
|
wakeup_when = self.sleep_until()
|
||||||
if wakeup_when is None:
|
if wakeup_when is None:
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
import sys
|
import sys
|
||||||
import errno
|
import errno
|
||||||
|
import signal
|
||||||
from eventlet import patcher
|
from eventlet import patcher
|
||||||
select = patcher.original('select')
|
select = patcher.original('select')
|
||||||
time = patcher.original('time')
|
time = patcher.original('time')
|
||||||
sleep = time.sleep
|
sleep = time.sleep
|
||||||
|
|
||||||
from eventlet.support import get_errno, clear_sys_exc_info
|
from eventlet.support import get_errno, clear_sys_exc_info
|
||||||
from eventlet.hubs.hub import BaseHub, READ, WRITE, noop
|
from eventlet.hubs.hub import BaseHub, READ, WRITE, noop, alarm_handler
|
||||||
|
|
||||||
EXC_MASK = select.POLLERR | select.POLLHUP
|
EXC_MASK = select.POLLERR | select.POLLHUP
|
||||||
READ_MASK = select.POLLIN | select.POLLPRI
|
READ_MASK = select.POLLIN | select.POLLPRI
|
||||||
@@ -82,6 +83,11 @@ class Hub(BaseHub):
|
|||||||
raise
|
raise
|
||||||
SYSTEM_EXCEPTIONS = self.SYSTEM_EXCEPTIONS
|
SYSTEM_EXCEPTIONS = self.SYSTEM_EXCEPTIONS
|
||||||
|
|
||||||
|
if self.debug_blocking:
|
||||||
|
# shortest alarm we can possibly set is one second
|
||||||
|
signal.signal(signal.SIGALRM, alarm_handler)
|
||||||
|
signal.alarm(1)
|
||||||
|
|
||||||
for fileno, event in presult:
|
for fileno, event in presult:
|
||||||
try:
|
try:
|
||||||
if event & READ_MASK:
|
if event & READ_MASK:
|
||||||
@@ -99,3 +105,7 @@ class Hub(BaseHub):
|
|||||||
except:
|
except:
|
||||||
self.squelch_exception(fileno, sys.exc_info())
|
self.squelch_exception(fileno, sys.exc_info())
|
||||||
clear_sys_exc_info()
|
clear_sys_exc_info()
|
||||||
|
|
||||||
|
if self.debug_blocking:
|
||||||
|
signal.alarm(0)
|
||||||
|
|
||||||
|
|||||||
@@ -142,6 +142,17 @@ class TestHubSelection(LimitedTestCase):
|
|||||||
hubs._threadlocal.hub = oldhub
|
hubs._threadlocal.hub = oldhub
|
||||||
|
|
||||||
|
|
||||||
|
class TestHubBlockingDetector(LimitedTestCase):
|
||||||
|
TEST_TIMEOUT = 10
|
||||||
|
def test_block_detect(self):
|
||||||
|
def look_im_blocking():
|
||||||
|
import time
|
||||||
|
time.sleep(2)
|
||||||
|
from eventlet import debug
|
||||||
|
debug.hub_blocking_detection(True)
|
||||||
|
gt = eventlet.spawn(look_im_blocking)
|
||||||
|
self.assertRaises(RuntimeError, gt.wait)
|
||||||
|
debug.hub_blocking_detection(False)
|
||||||
|
|
||||||
class Foo(object):
|
class Foo(object):
|
||||||
pass
|
pass
|
||||||
|
|||||||
Reference in New Issue
Block a user