summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZac Medico <zmedico@gentoo.org>2008-07-31 10:37:43 +0000
committerZac Medico <zmedico@gentoo.org>2008-07-31 10:37:43 +0000
commit5c673184186ff4061692fbbbfd852a2694df5cc4 (patch)
treef7746fe676dd4178b68ab9509d22f551507e399d
parentDescribe InheritSet and OwnerSet. (diff)
downloadportage-idfetch-5c673184186ff4061692fbbbfd852a2694df5cc4.tar.gz
portage-idfetch-5c673184186ff4061692fbbbfd852a2694df5cc4.tar.bz2
portage-idfetch-5c673184186ff4061692fbbbfd852a2694df5cc4.zip
Bug #233458 - Fix AsynchronousTask exit listener handling so that an exit
listener will never get called after it's been passed into removeExitListener(), since the caller of removeExitListener() needs to be able to be able to trust that the given exit listener will not be called under any circumstances. svn path=/main/trunk/; revision=11297
-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 e51f0c12..c99dfb09 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):