diff --git a/playground/maxjobs/bar.a b/playground/maxjobs/bar.a new file mode 100644 index 00000000..40c8025f --- /dev/null +++ b/playground/maxjobs/bar.a @@ -0,0 +1 @@ +aaaah!!! diff --git a/playground/maxjobs/foo.a b/playground/maxjobs/foo.a new file mode 100644 index 00000000..d8ba30fc --- /dev/null +++ b/playground/maxjobs/foo.a @@ -0,0 +1 @@ +aaaaa! diff --git a/playground/maxjobs/truc.a b/playground/maxjobs/truc.a new file mode 100644 index 00000000..0ef57795 --- /dev/null +++ b/playground/maxjobs/truc.a @@ -0,0 +1 @@ +aaaaaaaa!!!!! diff --git a/playground/maxjobs/wscript b/playground/maxjobs/wscript new file mode 100644 index 00000000..fe202fb5 --- /dev/null +++ b/playground/maxjobs/wscript @@ -0,0 +1,65 @@ +#! /usr/bin/env python + +# the Task class attribute "maxjobs" was deprecated in Waf 1.6 +# limiting the amount of jobs is commonly done by adding sequential +# barriers (build groups) or even locks. But the feature might be +# necessary in very few corner cases + +# in the following examples, remember that the method run() is the only +# one actually executed by threads + +def configure(conf): + pass + +def build(bld): + bld.jobs = 4 + bld(source='foo.a bar.a truc.a') + + +import threading, time +from waflib.TaskGen import extension +from waflib import Task + +@extension('.a') +def process_a_files(self, node): + self.create_task('a_to_b', node, node.change_ext('b')) + self.create_task('b_to_c', node.change_ext('b'), node.change_ext('c')) + +class a_to_b(Task.Task): + # classical way, using a lock or a semaphore + # in this case, at most 2 tasks can execute at a time + # this may lead to build starvation, as may tasks can get stalled while processing + + lock = threading.Semaphore(2) + def run(self): + try: + self.lock.acquire() + for i in range(5): + print('a to b %r' % id(self)) + time.sleep(1) + self.outputs[0].write('done') + finally: + self.lock.release() + + +class b_to_c(Task.Task): + # this will enable other tasks to run concurrently, and without additional locks + + active = [] + def runnable_status(self): + ret = Task.Task.runnable_status(self) + if ret == Task.RUN_ME: + self.active = [tsk for tsk in self.active if not tsk.hasrun] + if len(self.active) < 2: + self.active.append(self) + else: + # too many tasks are still active, wait + ret = Task.ASK_LATER + return ret + + def run(self): + for i in range(5): + print('b to c %r' % id(self)) + time.sleep(1) + self.outputs[0].write('done') +