Job.py (scons-4.2.0) | : | Job.py (SCons-4.3.0) | ||
---|---|---|---|---|
skipping to change at line 36 | skipping to change at line 36 | |||
The Jobs class provides a higher level interface to start, | The Jobs class provides a higher level interface to start, | |||
stop, and wait on jobs. | stop, and wait on jobs. | |||
""" | """ | |||
import SCons.compat | import SCons.compat | |||
import os | import os | |||
import signal | import signal | |||
import SCons.Errors | import SCons.Errors | |||
import SCons.Warnings | ||||
# The default stack size (in kilobytes) of the threads used to execute | # The default stack size (in kilobytes) of the threads used to execute | |||
# jobs in parallel. | # jobs in parallel. | |||
# | # | |||
# We use a stack size of 256 kilobytes. The default on some platforms | # We use a stack size of 256 kilobytes. The default on some platforms | |||
# is too large and prevents us from creating enough threads to fully | # is too large and prevents us from creating enough threads to fully | |||
# parallelized the build. For example, the default stack size on linux | # parallelized the build. For example, the default stack size on linux | |||
# is 8 MBytes. | # is 8 MBytes. | |||
explicit_stack_size = None | explicit_stack_size = None | |||
skipping to change at line 140 | skipping to change at line 141 | |||
Note also that we have to be careful to handle the case when | Note also that we have to be careful to handle the case when | |||
SCons forks before executing another process. In that case, we | SCons forks before executing another process. In that case, we | |||
want the child to exit immediately. | want the child to exit immediately. | |||
""" | """ | |||
def handler(signum, stack, self=self, parentpid=os.getpid()): | def handler(signum, stack, self=self, parentpid=os.getpid()): | |||
if os.getpid() == parentpid: | if os.getpid() == parentpid: | |||
self.job.taskmaster.stop() | self.job.taskmaster.stop() | |||
self.job.interrupted.set() | self.job.interrupted.set() | |||
else: | else: | |||
os._exit(2) | os._exit(2) # pylint: disable=protected-access | |||
self.old_sigint = signal.signal(signal.SIGINT, handler) | self.old_sigint = signal.signal(signal.SIGINT, handler) | |||
self.old_sigterm = signal.signal(signal.SIGTERM, handler) | self.old_sigterm = signal.signal(signal.SIGTERM, handler) | |||
try: | try: | |||
self.old_sighup = signal.signal(signal.SIGHUP, handler) | self.old_sighup = signal.signal(signal.SIGHUP, handler) | |||
except AttributeError: | except AttributeError: | |||
pass | pass | |||
if (self.old_sigint is None) or (self.old_sigterm is None) or \ | ||||
(hasattr(self, "old_sighup") and self.old_sighup is None): | ||||
msg = "Overwritting previous signal handler which was not installed | ||||
from Python. " + \ | ||||
"Will not be able to reinstate and so will return to default han | ||||
dler." | ||||
SCons.Warnings.warn(SCons.Warnings.SConsWarning, msg) | ||||
def _reset_sig_handler(self): | def _reset_sig_handler(self): | |||
"""Restore the signal handlers to their previous state (before the | """Restore the signal handlers to their previous state (before the | |||
call to _setup_sig_handler().""" | call to _setup_sig_handler().""" | |||
sigint_to_use = self.old_sigint if self.old_sigint is not None else sign | ||||
signal.signal(signal.SIGINT, self.old_sigint) | al.SIG_DFL | |||
signal.signal(signal.SIGTERM, self.old_sigterm) | sigterm_to_use = self.old_sigterm if self.old_sigterm is not None else s | |||
ignal.SIG_DFL | ||||
signal.signal(signal.SIGINT, sigint_to_use) | ||||
signal.signal(signal.SIGTERM, sigterm_to_use) | ||||
try: | try: | |||
signal.signal(signal.SIGHUP, self.old_sighup) | sigterm_to_use = self.old_sighup if self.old_sighup is not None else | |||
signal.SIG_DFL | ||||
signal.signal(signal.SIGHUP, sigterm_to_use) | ||||
except AttributeError: | except AttributeError: | |||
pass | pass | |||
class Serial: | class Serial: | |||
"""This class is used to execute tasks in series, and is more efficient | """This class is used to execute tasks in series, and is more efficient | |||
than Parallel, but is only appropriate for non-parallel builds. Only | than Parallel, but is only appropriate for non-parallel builds. Only | |||
one instance of this class should be in existence at a time. | one instance of this class should be in existence at a time. | |||
This class is not thread safe. | This class is not thread safe. | |||
""" | """ | |||
skipping to change at line 231 | skipping to change at line 239 | |||
except ImportError: | except ImportError: | |||
pass | pass | |||
else: | else: | |||
class Worker(threading.Thread): | class Worker(threading.Thread): | |||
"""A worker thread waits on a task to be posted to its request queue, | """A worker thread waits on a task to be posted to its request queue, | |||
dequeues the task, executes it, and posts a tuple including the task | dequeues the task, executes it, and posts a tuple including the task | |||
and a boolean indicating whether the task executed successfully. """ | and a boolean indicating whether the task executed successfully. """ | |||
def __init__(self, requestQueue, resultsQueue, interrupted): | def __init__(self, requestQueue, resultsQueue, interrupted): | |||
threading.Thread.__init__(self) | threading.Thread.__init__(self) | |||
self.setDaemon(1) | self.daemon = True | |||
self.requestQueue = requestQueue | self.requestQueue = requestQueue | |||
self.resultsQueue = resultsQueue | self.resultsQueue = resultsQueue | |||
self.interrupted = interrupted | self.interrupted = interrupted | |||
self.start() | self.start() | |||
def run(self): | def run(self): | |||
while True: | while True: | |||
task = self.requestQueue.get() | task = self.requestQueue.get() | |||
if task is None: | if task is None: | |||
skipping to change at line 389 | skipping to change at line 397 | |||
# prepare task for execution | # prepare task for execution | |||
task.prepare() | task.prepare() | |||
except: | except: | |||
task.exception_set() | task.exception_set() | |||
task.failed() | task.failed() | |||
task.postprocess() | task.postprocess() | |||
else: | else: | |||
if task.needs_execute(): | if task.needs_execute(): | |||
# dispatch task | # dispatch task | |||
self.tp.put(task) | self.tp.put(task) | |||
jobs = jobs + 1 | jobs += 1 | |||
else: | else: | |||
task.executed() | task.executed() | |||
task.postprocess() | task.postprocess() | |||
if not task and not jobs: break | if not task and not jobs: break | |||
# Let any/all completed tasks finish up before we go | # Let any/all completed tasks finish up before we go | |||
# back and put the next batch of tasks on the queue. | # back and put the next batch of tasks on the queue. | |||
while True: | while True: | |||
task, ok = self.tp.get() | task, ok = self.tp.get() | |||
jobs = jobs - 1 | jobs -= 1 | |||
if ok: | if ok: | |||
task.executed() | task.executed() | |||
else: | else: | |||
if self.interrupted(): | if self.interrupted(): | |||
try: | try: | |||
raise SCons.Errors.BuildError( | raise SCons.Errors.BuildError( | |||
task.targets[0], errstr=interrupt_msg) | task.targets[0], errstr=interrupt_msg) | |||
except: | except: | |||
task.exception_set() | task.exception_set() | |||
End of changes. 8 change blocks. | ||||
8 lines changed or deleted | 21 lines changed or added |