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:
|
else:
|
||||||
timer.cancel()
|
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():
|
def get_default_hub():
|
||||||
|
@@ -45,6 +45,7 @@ class BaseHub(object):
|
|||||||
self.readers = {}
|
self.readers = {}
|
||||||
self.writers = {}
|
self.writers = {}
|
||||||
self.excs = {}
|
self.excs = {}
|
||||||
|
self.waiters_by_greenlet = {}
|
||||||
|
|
||||||
self.clock = clock
|
self.clock = clock
|
||||||
self.greenlet = None
|
self.greenlet = None
|
||||||
@@ -80,11 +81,19 @@ class BaseHub(object):
|
|||||||
self.readers[fileno] = read or self.readers.get(fileno)
|
self.readers[fileno] = read or self.readers.get(fileno)
|
||||||
self.writers[fileno] = write or self.writers.get(fileno)
|
self.writers[fileno] = write or self.writers.get(fileno)
|
||||||
self.excs[fileno] = exc or self.excs.get(fileno)
|
self.excs[fileno] = exc or self.excs.get(fileno)
|
||||||
|
self.waiters_by_greenlet[greenlet.getcurrent()] = fileno
|
||||||
|
|
||||||
def remove_descriptor(self, fileno):
|
def remove_descriptor(self, fileno):
|
||||||
self.readers.pop(fileno, None)
|
self.readers.pop(fileno, None)
|
||||||
self.writers.pop(fileno, None)
|
self.writers.pop(fileno, None)
|
||||||
self.excs.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):
|
def exc_descriptor(self, fileno):
|
||||||
exc = self.excs.get(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 = event.signal(signal.SIGINT, self.signal_received, signal.SIGINT)
|
||||||
sig.add()
|
sig.add()
|
||||||
|
|
||||||
|
|
||||||
def add_descriptor(self, fileno, read=None, write=None, exc=None):
|
def add_descriptor(self, fileno, read=None, write=None, exc=None):
|
||||||
if read:
|
if read:
|
||||||
evt = event.read(fileno, read, fileno)
|
evt = event.read(fileno, read, fileno)
|
||||||
@@ -74,12 +73,15 @@ class Hub(hub.BaseHub):
|
|||||||
if exc:
|
if exc:
|
||||||
self.excs[fileno] = exc
|
self.excs[fileno] = exc
|
||||||
|
|
||||||
|
self.waiters_by_greenlet[greenlet.getcurrent()] = fileno
|
||||||
|
|
||||||
def remove_descriptor(self, fileno):
|
def remove_descriptor(self, fileno):
|
||||||
for queue in (self.readers, self.writers):
|
for queue in (self.readers, self.writers):
|
||||||
tpl = queue.pop(fileno, None)
|
tpl = queue.pop(fileno, None)
|
||||||
if tpl is not None:
|
if tpl is not None:
|
||||||
tpl[0].delete()
|
tpl[0].delete()
|
||||||
self.excs.pop(fileno, None)
|
self.excs.pop(fileno, None)
|
||||||
|
self.waiters_by_greenlet.pop(greenlet.getcurrent(), None)
|
||||||
|
|
||||||
def abort(self):
|
def abort(self):
|
||||||
super(Hub, self).abort()
|
super(Hub, self).abort()
|
||||||
|
Reference in New Issue
Block a user