Added multiple-reader prevention code because it seems to be a fairly common pitfall. Also added defaults to the debug methods so you can call them no-args to reset them.

This commit is contained in:
Ryan Williams
2010-03-15 21:14:41 -07:00
parent 160580c155
commit cb7c8c0196
4 changed files with 46 additions and 4 deletions

View File

@@ -93,7 +93,7 @@ def format_hub_timers():
result.append(repr(l))
return os.linesep.join(result)
def hub_listener_stacks(state):
def hub_listener_stacks(state = False):
"""Toggles whether or not the hub records the stack when clients register
listeners on file descriptors. This can be useful when trying to figure
out what the hub is up to at any given moment. To inspect the stacks
@@ -103,15 +103,19 @@ def hub_listener_stacks(state):
from eventlet import hubs
hubs.get_hub().set_debug_listeners(state)
def hub_timer_stacks(state):
def hub_timer_stacks(state = False):
"""Toggles whether or not the hub records the stack when timers are set.
To inspect the stacks of the current timers, call :func:`format_hub_timers`
at critical junctures in the application logic.
"""
from eventlet.hubs import timer
timer._g_debug = state
def hub_prevent_multiple_readers(state = True):
from eventlet.hubs import hub
hub.g_prevent_multiple_readers = state
def hub_exceptions(state):
def hub_exceptions(state = True):
"""Toggles whether the hub prints exceptions that are raised from its
timers. This can be useful to see how greenthreads are terminating.
"""
@@ -120,7 +124,7 @@ def hub_exceptions(state):
from eventlet import greenpool
greenpool.DEBUG = state
def tpool_exceptions(state):
def tpool_exceptions(state = False):
"""Toggles whether tpool itself prints exceptions that are raised from
functions that are executed in it, in addition to raising them like
it normally does."""

View File

@@ -1,12 +1,15 @@
import heapq
import sys
import traceback
import warnings
from eventlet.support import greenlets as greenlet, clear_sys_exc_info
from eventlet.hubs import timer
from eventlet import patcher
time = patcher.original('time')
g_prevent_multiple_readers = True
READ="read"
WRITE="write"
@@ -74,6 +77,15 @@ class BaseHub(object):
listener = self.lclass(evtype, fileno, cb)
bucket = self.listeners[evtype]
if fileno in bucket:
if g_prevent_multiple_readers:
raise RuntimeError("Second simultaneous %s on fileno %s "\
"detected. Unless you really know what you're doing, "\
"make sure that only one greenthread can %s any "\
"particular socket. Consider using a pools.Pool. "\
"If you do know what you're doing and want to disable "\
"this error, call "\
"eventlet.debug.hub_multiple_reader_prevention(False)" % (
evtype, fileno, evtype))
# store off the second listener in another structure
self.secondaries[evtype].setdefault(fileno, []).append(listener)
else:

View File

@@ -483,11 +483,34 @@ class TestGreenIo(LimitedTestCase):
gt.wait()
@skip_with_pyevent
def test_raised_multiple_readers(self):
debug.hub_prevent_multiple_readers(True)
def handle(sock, addr):
sock.recv(1)
sock.sendall("a")
raise eventlet.StopServe()
listener = eventlet.listen(('127.0.0.1', 0))
server = eventlet.spawn(eventlet.serve,
listener,
handle)
def reader(s):
s.recv(1)
s = eventlet.connect(('127.0.0.1', listener.getsockname()[1]))
a = eventlet.spawn(reader, s)
eventlet.sleep(0)
self.assertRaises(RuntimeError, s.recv, 1)
s.sendall('b')
a.wait()
class TestGreenIoLong(LimitedTestCase):
TEST_TIMEOUT=10 # the test here might take a while depending on the OS
@skip_with_pyevent
def test_multiple_readers(self, clibufsize=False):
debug.hub_prevent_multiple_readers(False)
recvsize = 2 * min_buf_size()
sendsize = 10 * recvsize
# test that we can have multiple coroutines reading
@@ -534,6 +557,7 @@ class TestGreenIoLong(LimitedTestCase):
listener.close()
self.assert_(len(results1) > 0)
self.assert_(len(results2) > 0)
debug.hub_prevent_multiple_readers()
@skipped # by rdw because it fails but it's not clear how to make it pass
@skip_with_pyevent

View File

@@ -3,6 +3,8 @@
Many of these tests make connections to external servers, and all.py tries to skip these tests rather than failing them, so you can get some work done on a plane.
"""
from eventlet import debug
debug.hub_prevent_multiple_readers(False)
def restart_hub():
from eventlet import hubs