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:
parent
c10875d7d7
commit
116e7e5f13
2 changed files with 42 additions and 33 deletions
20
jwack.py
20
jwack.py
|
|
@ -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
55
redo.py
|
|
@ -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:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue