summaryrefslogtreecommitdiffstats
path: root/pym/_emerge/AsynchronousTask.py
diff options
context:
space:
mode:
authorZac Medico <zmedico@gentoo.org>2009-06-22 16:43:52 +0000
committerZac Medico <zmedico@gentoo.org>2009-06-22 16:43:52 +0000
commitd057d91f391981fb0564873c471d550f2f62edf5 (patch)
treed6cd416fc5e9389806ec98a02ae236c99e876e4b /pym/_emerge/AsynchronousTask.py
parent28184c982a0688ed9bc4d82df407d4e400f6318c (diff)
downloadportage-d057d91f391981fb0564873c471d550f2f62edf5.tar.gz
portage-d057d91f391981fb0564873c471d550f2f62edf5.tar.bz2
portage-d057d91f391981fb0564873c471d550f2f62edf5.zip
Bug #275047 - Split _emerge/__init__.py into smaller pieces. Thanks to
Sebastian Mingramm (few) <s.mingramm@gmx.de> for this patch. svn path=/main/trunk/; revision=13663
Diffstat (limited to 'pym/_emerge/AsynchronousTask.py')
-rw-r--r--pym/_emerge/AsynchronousTask.py112
1 files changed, 112 insertions, 0 deletions
diff --git a/pym/_emerge/AsynchronousTask.py b/pym/_emerge/AsynchronousTask.py
new file mode 100644
index 000000000..089e1acfc
--- /dev/null
+++ b/pym/_emerge/AsynchronousTask.py
@@ -0,0 +1,112 @@
+from _emerge.SlotObject import SlotObject
+class AsynchronousTask(SlotObject):
+ """
+ Subclasses override _wait() and _poll() so that calls
+ to public methods can be wrapped for implementing
+ hooks such as exit listener notification.
+
+ Sublasses should call self.wait() to notify exit listeners after
+ the task is complete and self.returncode has been set.
+ """
+
+ __slots__ = ("background", "cancelled", "returncode") + \
+ ("_exit_listeners", "_exit_listener_stack", "_start_listeners")
+
+ def start(self):
+ """
+ Start an asynchronous task and then return as soon as possible.
+ """
+ self._start_hook()
+ self._start()
+
+ def _start(self):
+ raise NotImplementedError(self)
+
+ def isAlive(self):
+ return self.returncode is None
+
+ def poll(self):
+ self._wait_hook()
+ return self._poll()
+
+ def _poll(self):
+ return self.returncode
+
+ def wait(self):
+ if self.returncode is None:
+ self._wait()
+ self._wait_hook()
+ return self.returncode
+
+ def _wait(self):
+ return self.returncode
+
+ def cancel(self):
+ self.cancelled = True
+ self.wait()
+
+ def addStartListener(self, f):
+ """
+ The function will be called with one argument, a reference to self.
+ """
+ if self._start_listeners is None:
+ self._start_listeners = []
+ self._start_listeners.append(f)
+
+ def removeStartListener(self, f):
+ if self._start_listeners is None:
+ return
+ self._start_listeners.remove(f)
+
+ def _start_hook(self):
+ if self._start_listeners is not None:
+ start_listeners = self._start_listeners
+ self._start_listeners = None
+
+ for f in start_listeners:
+ f(self)
+
+ def addExitListener(self, f):
+ """
+ The function will be called with one argument, a reference to self.
+ """
+ if self._exit_listeners is None:
+ self._exit_listeners = []
+ self._exit_listeners.append(f)
+
+ 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)
+
+ def _wait_hook(self):
+ """
+ Call this method after the task completes, just before returning
+ the returncode from wait() or poll(). This hook is
+ used to trigger exit listeners when the returncode first
+ becomes available.
+ """
+ if self.returncode is not None and \
+ self._exit_listeners is not None:
+
+ # This prevents recursion, in case one of the
+ # exit handlers triggers this method again by
+ # 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
+
+ self._exit_listener_stack.reverse()
+ while self._exit_listener_stack:
+ self._exit_listener_stack.pop()(self)
+