Probably horribly broken block detecter, only for poll/epoll hubs.

This commit is contained in:
Ryan Williams
2010-05-07 00:30:53 -07:00
parent 6803ea3afc
commit 3bc3563f94
4 changed files with 57 additions and 2 deletions

View File

@@ -130,3 +130,14 @@ def tpool_exceptions(state = False):
it normally does."""
from eventlet import tpool
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()

View File

@@ -2,6 +2,7 @@ import heapq
import sys
import traceback
import warnings
import signal
from eventlet.support import greenlets as greenlet, clear_sys_exc_info
from eventlet.hubs import timer
@@ -42,6 +43,11 @@ class DebugListener(FdListener):
__str__ = __repr__
def alarm_handler(signum, frame):
import inspect
raise RuntimeError("ALARMED at" + str(inspect.getframeinfo(frame)))
class BaseHub(object):
""" Base hub class for easing the implementation of subclasses that are
specific to a particular underlying event architecture. """
@@ -62,8 +68,21 @@ class BaseHub(object):
self.timers = []
self.next_timers = []
self.lclass = FdListener
self.debug_exceptions = True
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):
""" Signals an intent to or write a particular file descriptor.
@@ -166,7 +185,11 @@ class BaseHub(object):
self.stopping = False
while not self.stopping:
self.prepare_timers()
if self.debug_blocking:
self.block_detect_pre()
self.fire_timers(self.clock())
if self.debug_blocking:
self.block_detect_post()
self.prepare_timers()
wakeup_when = self.sleep_until()
if wakeup_when is None:

View File

@@ -1,12 +1,13 @@
import sys
import errno
import signal
from eventlet import patcher
select = patcher.original('select')
time = patcher.original('time')
sleep = time.sleep
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
READ_MASK = select.POLLIN | select.POLLPRI
@@ -82,6 +83,11 @@ class Hub(BaseHub):
raise
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:
try:
if event & READ_MASK:
@@ -99,3 +105,7 @@ class Hub(BaseHub):
except:
self.squelch_exception(fileno, sys.exc_info())
clear_sys_exc_info()
if self.debug_blocking:
signal.alarm(0)

View File

@@ -142,6 +142,17 @@ class TestHubSelection(LimitedTestCase):
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):
pass