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