summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--pym/_emerge/__init__.py22
1 files changed, 17 insertions, 5 deletions
diff --git a/pym/_emerge/__init__.py b/pym/_emerge/__init__.py
index e51f0c12e..c99dfb09a 100644
--- a/pym/_emerge/__init__.py
+++ b/pym/_emerge/__init__.py
@@ -1599,7 +1599,7 @@ class AsynchronousTask(SlotObject):
"""
__slots__ = ("background", "cancelled", "returncode") + \
- ("_exit_listeners", "_start_listeners")
+ ("_exit_listeners", "_exit_listener_stack", "_start_listeners")
def start(self):
"""
@@ -1665,6 +1665,8 @@ class AsynchronousTask(SlotObject):
def removeExitListener(self, f):
if self._exit_listeners is None:
+ if self._exit_listener_stack is not None:
+ self._exit_listener_stack.remove(f)
return
self._exit_listeners.remove(f)
@@ -1680,12 +1682,22 @@ class AsynchronousTask(SlotObject):
# This prevents recursion, in case one of the
# exit handlers triggers this method again by
- # calling wait().
- exit_listeners = self._exit_listeners
+ # calling wait(). Use a stack that gives
+ # removeExitListener() an opportunity to consume
+ # listeners from the stack, before they can get
+ # called below. This is necessary because a call
+ # to one exit listener may result in a call to
+ # removeExitListener() for another listener on
+ # the stack. That listener needs to be removed
+ # from the stack since it would be inconsistent
+ # to call it after it has been been passed into
+ # removeExitListener().
+ self._exit_listener_stack = self._exit_listeners
self._exit_listeners = None
- for f in exit_listeners:
- f(self)
+ self._exit_listener_stack.reverse()
+ while self._exit_listener_stack:
+ self._exit_listener_stack.pop()(self)
class PipeReader(AsynchronousTask):