We now check the lock before releasing our jwack token.

That way, if everything is locked, we can determine that with a single
token, reducing context switches.

But mostly this is good because the code is simpler.
This commit is contained in:
Avery Pennarun 2010-11-19 07:09:26 -08:00
commit 116e7e5f13
2 changed files with 42 additions and 33 deletions

View file

@ -105,10 +105,10 @@ def wait(want_token):
def get_token(reason): def get_token(reason):
global _mytokens global _mytokens
setup(1)
while 1: while 1:
if _mytokens >= 1: if _mytokens >= 1:
_debug('(%r) used my own token...\n' % reason) _debug('(%r) used my own token...\n' % reason)
_mytokens -= 1
return return
_debug('(%r) waiting for tokens...\n' % reason) _debug('(%r) waiting for tokens...\n' % reason)
wait(want_token=1) wait(want_token=1)
@ -118,6 +118,7 @@ def get_token(reason):
raise Exception('unexpected EOF on token read') raise Exception('unexpected EOF on token read')
if b: if b:
break break
_mytokens += 1
_debug('(%r) got a token (%r).\n' % (reason, b)) _debug('(%r) got a token (%r).\n' % (reason, b))
@ -171,24 +172,29 @@ class Job:
return 'Job(%s,%d)' % (self.name, self.pid) return 'Job(%s,%d)' % (self.name, self.pid)
def start_job(reason, jobfunc, donefunc): def start_job(reason, lock, jobfunc, donefunc):
setup(1) global _mytokens
assert(lock.owned)
get_token(reason) get_token(reason)
assert(_mytokens >= 1)
_mytokens -= 1
r,w = os.pipe() r,w = os.pipe()
pid = os.fork() pid = os.fork()
if pid == 0: if pid == 0:
# child # child
os.close(r) os.close(r)
rv = 201
try: try:
try: try:
jobfunc() rv = jobfunc() or 0
os._exit(0) except Exception:
except Exception, e:
import traceback import traceback
traceback.print_exc() traceback.print_exc()
lock.unlock()
finally: finally:
os._exit(201) os._exit(rv)
# else we're the parent process # else we're the parent process
lock.owned = False # child owns it now
os.close(w) os.close(w)
pd = Job(reason, pid, donefunc) pd = Job(reason, pid, donefunc)
_waitfds[r] = pd _waitfds[r] = pd

55
redo.py
View file

@ -140,22 +140,14 @@ def _build(t):
def build(t): def build(t):
lock = state.Lock(t)
lock.trylock()
if not lock.owned:
log('%s (locked...)\n' % relpath(t, vars.STARTDIR))
os._exit(199)
try: try:
try: return _build(t)
return _build(t) except BuildError, e:
except BuildError, e: err('%s\n' % e)
err('%s\n' % e) return 1
finally:
lock.unlock()
os._exit(1)
def main(): def main(targets, buildfunc):
retcode = [0] # a list so that it can be reassigned from done() retcode = [0] # a list so that it can be reassigned from done()
if vars.SHUFFLE: if vars.SHUFFLE:
random.shuffle(targets) random.shuffle(targets)
@ -169,30 +161,41 @@ def main():
err('%s: exit code was %r\n' % (t, rv)) err('%s: exit code was %r\n' % (t, rv))
retcode[0] = 1 retcode[0] = 1
for t in targets: for i in range(len(targets)):
t = targets[i]
if os.path.exists('%s/all.do' % t): if os.path.exists('%s/all.do' % t):
# t is a directory, but it has a default target # t is a directory, but it has a default target
t = '%s/all' % t targets[i] = '%s/all' % t
tt = t
jwack.start_job(t, lambda: build(t), lambda t,rv: done(t,rv)) for t in targets:
jwack.get_token(t)
lock = state.Lock(t)
lock.trylock()
if not lock.owned:
log('%s (locked...)\n' % relpath(t, vars.STARTDIR))
locked.append(t)
else:
jwack.start_job(t, lock,
lambda: buildfunc(t), lambda t,rv: done(t,rv))
while locked or jwack.running(): while locked or jwack.running():
jwack.wait_all() jwack.wait_all()
if locked: if locked:
t = locked.pop(0) t = locked.pop(0)
l = state.Lock(t) lock = state.Lock(t)
while not l.owned: while not lock.owned:
l.wait() lock.wait()
l.trylock() lock.trylock()
assert(l.owned) assert(lock.owned)
relp = relpath(t, vars.STARTDIR) relp = relpath(t, vars.STARTDIR)
log('%s (...unlocked!)\n' % relp) log('%s (...unlocked!)\n' % relp)
if state.stamped(t) == None: if state.stamped(t) == None:
err('%s: failed in another thread\n' % relp) err('%s: failed in another thread\n' % relp)
retcode[0] = 2 retcode[0] = 2
l.unlock() lock.unlock()
else: else:
l.unlock() # build() reacquires it jwack.start_job(t, lock,
jwack.start_job(t, lambda: build(t), lambda t,rv: done(t,rv)) lambda: buildfunc(t), lambda t,rv: done(t,rv))
return retcode[0] return retcode[0]
@ -210,7 +213,7 @@ try:
err('invalid --jobs value: %r\n' % opt.jobs) err('invalid --jobs value: %r\n' % opt.jobs)
jwack.setup(j) jwack.setup(j)
try: try:
retcode = main() retcode = main(targets, build)
finally: finally:
jwack.force_return_tokens() jwack.force_return_tokens()
if retcode: if retcode: