summaryrefslogtreecommitdiffstats
path: root/pym
diff options
context:
space:
mode:
authorZac Medico <zmedico@gentoo.org>2012-02-12 22:43:46 -0800
committerZac Medico <zmedico@gentoo.org>2012-02-12 22:43:46 -0800
commit8346a62a08c91de8b7672faa0ebfb91d0e647fa0 (patch)
tree7a880ea7ba9d4ce95cd340d84987af051b9f6135 /pym
parent9997bb9c81e0742060dc795e4e0397db4cbfb5c2 (diff)
downloadportage-8346a62a08c91de8b7672faa0ebfb91d0e647fa0.tar.gz
portage-8346a62a08c91de8b7672faa0ebfb91d0e647fa0.tar.bz2
portage-8346a62a08c91de8b7672faa0ebfb91d0e647fa0.zip
PollScheduler: use idle_add to check termination
This fixes a regression in termination signal handling since commit 8c1fcf5a9ba9fa4d406a4d0cc284fe73a84f5a63, which cause termination signals to be ignored until a running job had exited. This regression is not really noticeable for Ctrl-C handling, since in that case the SIGINT propagets to subprocesses, causing them to exit and trigger a _schedule() call whichtriggers a termination check.
Diffstat (limited to 'pym')
-rw-r--r--pym/_emerge/PollScheduler.py61
-rw-r--r--pym/_emerge/QueueScheduler.py2
2 files changed, 41 insertions, 22 deletions
diff --git a/pym/_emerge/PollScheduler.py b/pym/_emerge/PollScheduler.py
index e270e6ad0..1db68072c 100644
--- a/pym/_emerge/PollScheduler.py
+++ b/pym/_emerge/PollScheduler.py
@@ -59,11 +59,30 @@ class PollScheduler(object):
"""
self._terminated.set()
+ def _termination_check(self):
+ """
+ Calls _terminate_tasks() if appropriate. It's guaranteed not to
+ call it while _schedule_tasks() is being called. The check should
+ be executed for each iteration of the event loop, for response to
+ termination signals at the earliest opportunity. It always returns
+ True, for continuous scheduling via idle_add.
+ """
+ if not self._scheduling and \
+ self._terminated.is_set() and \
+ not self._terminated_tasks:
+ self._scheduling = True
+ try:
+ self._terminated_tasks = True
+ self._terminate_tasks()
+ finally:
+ self._scheduling = False
+ return True
+
def _terminate_tasks(self):
"""
Send signals to terminate all tasks. This is called once
- from self._schedule() in the event dispatching thread. This
- prevents it from being called while the _schedule_tasks()
+ from _keep_scheduling() or _is_work_scheduled() in the event
+ dispatching thread. It will not be called while the _schedule_tasks()
implementation is running, in order to avoid potential
interference. All tasks should be cleaned up at the earliest
opportunity, but not necessarily before this method returns.
@@ -107,31 +126,29 @@ class PollScheduler(object):
return False
self._scheduling = True
try:
-
- if self._terminated.is_set() and \
- not self._terminated_tasks:
- self._terminated_tasks = True
- self._terminate_tasks()
-
self._schedule_tasks()
finally:
self._scheduling = False
def _main_loop(self):
- # Populate initial event sources. We only need to do
- # this once here, since it can be called during the
- # loop from within event handlers.
- self._schedule()
-
- # Loop while there are jobs to be scheduled.
- while self._keep_scheduling():
- self.sched_iface.iteration()
-
- # Clean shutdown of previously scheduled jobs. In the
- # case of termination, this allows for basic cleanup
- # such as flushing of buffered output to logs.
- while self._is_work_scheduled():
- self.sched_iface.iteration()
+ term_check_id = self.sched_iface.idle_add(self._termination_check)
+ try:
+ # Populate initial event sources. We only need to do
+ # this once here, since it can be called during the
+ # loop from within event handlers.
+ self._schedule()
+
+ # Loop while there are jobs to be scheduled.
+ while self._keep_scheduling():
+ self.sched_iface.iteration()
+
+ # Clean shutdown of previously scheduled jobs. In the
+ # case of termination, this allows for basic cleanup
+ # such as flushing of buffered output to logs.
+ while self._is_work_scheduled():
+ self.sched_iface.iteration()
+ finally:
+ self.sched_iface.source_remove(term_check_id)
def _is_work_scheduled(self):
return bool(self._running_job_count())
diff --git a/pym/_emerge/QueueScheduler.py b/pym/_emerge/QueueScheduler.py
index 731a677e5..730bd787d 100644
--- a/pym/_emerge/QueueScheduler.py
+++ b/pym/_emerge/QueueScheduler.py
@@ -43,6 +43,7 @@ class QueueScheduler(PollScheduler):
timeout_callback.timeout_id = self.sched_iface.timeout_add(
timeout, timeout_callback)
+ term_check_id = self.sched_iface.idle_add(self._termination_check)
try:
while not (timeout_callback is not None and
timeout_callback.timed_out):
@@ -59,6 +60,7 @@ class QueueScheduler(PollScheduler):
timeout_callback.timed_out):
self.sched_iface.iteration()
finally:
+ self.sched_iface.source_remove(term_check_id)
if timeout_callback is not None:
self.sched_iface.unregister(timeout_callback.timeout_id)