Fix another common cause of SwitchingToDeadGreenlet or _socketobject is not iterable. Using exc_after to cancel a socket operation would leave the socket's fd in the hub, causing a spurious resumption of that greenlet when the socket operation completed in the future.

This commit is contained in:
donovan
2008-06-25 15:26:00 -07:00
parent f56c764b78
commit 135d2ad865
3 changed files with 14 additions and 2 deletions

View File

@@ -295,7 +295,8 @@ def exc_after(seconds, exception_object):
else:
timer.cancel()
"""
return call_after(seconds, switch, getcurrent(), None, exception_object)
hub = get_hub()
return call_after(seconds, hub.exc_greenlet, getcurrent(), exception_object)
def get_default_hub():

View File

@@ -45,6 +45,7 @@ class BaseHub(object):
self.readers = {}
self.writers = {}
self.excs = {}
self.waiters_by_greenlet = {}
self.clock = clock
self.greenlet = None
@@ -80,11 +81,19 @@ class BaseHub(object):
self.readers[fileno] = read or self.readers.get(fileno)
self.writers[fileno] = write or self.writers.get(fileno)
self.excs[fileno] = exc or self.excs.get(fileno)
self.waiters_by_greenlet[greenlet.getcurrent()] = fileno
def remove_descriptor(self, fileno):
self.readers.pop(fileno, None)
self.writers.pop(fileno, None)
self.excs.pop(fileno, None)
self.waiters_by_greenlet.pop(greenlet.getcurrent(), None)
def exc_greenlet(self, gr, exception_object):
fileno = self.waiters_by_greenlet.pop(gr, None)
if fileno is not None:
self.remove_descriptor(fileno)
greenlib.switch(gr, None, exception_object)
def exc_descriptor(self, fileno):
exc = self.excs.get(fileno)

View File

@@ -59,7 +59,6 @@ class Hub(hub.BaseHub):
sig = event.signal(signal.SIGINT, self.signal_received, signal.SIGINT)
sig.add()
def add_descriptor(self, fileno, read=None, write=None, exc=None):
if read:
evt = event.read(fileno, read, fileno)
@@ -74,12 +73,15 @@ class Hub(hub.BaseHub):
if exc:
self.excs[fileno] = exc
self.waiters_by_greenlet[greenlet.getcurrent()] = fileno
def remove_descriptor(self, fileno):
for queue in (self.readers, self.writers):
tpl = queue.pop(fileno, None)
if tpl is not None:
tpl[0].delete()
self.excs.pop(fileno, None)
self.waiters_by_greenlet.pop(greenlet.getcurrent(), None)
def abort(self):
super(Hub, self).abort()