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:
		@@ -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."""
 | 
			
		||||
 
 | 
			
		||||
@@ -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:
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user