From 5c673184186ff4061692fbbbfd852a2694df5cc4 Mon Sep 17 00:00:00 2001 From: Zac Medico Date: Thu, 31 Jul 2008 10:37:43 +0000 Subject: 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 --- pym/_emerge/__init__.py | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) (limited to 'pym/_emerge') 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): -- cgit v1.2.3-1-g7c22