diff --git a/builder.py b/builder.py index 4d13357..0abadde 100644 --- a/builder.py +++ b/builder.py @@ -124,7 +124,9 @@ def main(targets, buildfunc): if os.path.exists('%s/all.do' % t): # t is a directory, but it has a default target targets[i] = '%s/all' % t - + + # In the first cycle, we just build as much as we can without worrying + # about any lock contention. If someone else has it locked, we move on. for t in targets: jwack.get_token(t) if retcode[0] and not vars.KEEP_GOING: @@ -138,7 +140,11 @@ def main(targets, buildfunc): else: jwack.start_job(t, lock, lambda: buildfunc(t), lambda t,rv: done(t,rv)) - + + # Now we've built all the "easy" ones. Go back and just wait on the + # remaining ones one by one. This is technically non-optimal; we could + # use select.select() to wait on more than one at a time. But it should + # be rare enough that it doesn't matter, and the logic is easier this way. while locked or jwack.running(): jwack.wait_all() if retcode[0] and not vars.KEEP_GOING: @@ -146,9 +152,7 @@ def main(targets, buildfunc): if locked: t = locked.pop(0) lock = state.Lock(t) - while not lock.owned: - lock.wait() - lock.trylock() + lock.waitlock() assert(lock.owned) if vars.DEBUG_LOCKS: log('%s (...unlocked!)\n' % _nice(t)) diff --git a/jwack.py b/jwack.py index f585637..4bf11ab 100644 --- a/jwack.py +++ b/jwack.py @@ -107,21 +107,29 @@ def wait(want_token): def get_token(reason): global _mytokens + assert(_mytokens <= 1) setup(1) while 1: if _mytokens >= 1: + _debug("_mytokens is %d\n" % _mytokens) + assert(_mytokens == 1) _debug('(%r) used my own token...\n' % reason) - return + break + assert(_mytokens < 1) _debug('(%r) waiting for tokens...\n' % reason) wait(want_token=1) + if _mytokens >= 1: + break + assert(_mytokens < 1) if _fds: b = _try_read(_fds[0], 1) if b == None: raise Exception('unexpected EOF on token read') if b: + _mytokens += 1 + _debug('(%r) got a token (%r).\n' % (reason, b)) break - _mytokens += 1 - _debug('(%r) got a token (%r).\n' % (reason, b)) + assert(_mytokens <= 1) def running(): @@ -177,8 +185,10 @@ class Job: def start_job(reason, lock, jobfunc, donefunc): global _mytokens assert(lock.owned) + assert(_mytokens <= 1) get_token(reason) assert(_mytokens >= 1) + assert(_mytokens == 1) _mytokens -= 1 r,w = os.pipe() pid = os.fork() diff --git a/state.py b/state.py index f9c21f6..4e4da25 100644 --- a/state.py +++ b/state.py @@ -162,6 +162,12 @@ class Lock: else: raise + def waitlock(self): + while not self.owned: + self.wait() + self.trylock() + assert(self.owned) + def unlock(self): if not self.owned: raise Exception("can't unlock %r - we don't own it"