Add at 'X' attribute to indicate rules that are not to be run concurrently with anything
This commit is contained in:
parent
782a73e0d9
commit
1eb840af57
3 changed files with 57 additions and 14 deletions
66
mk.go
66
mk.go
|
|
@ -24,24 +24,54 @@ const maxRuleCnt = 1
|
|||
|
||||
// Limit the number of recipes executed simultaneously.
|
||||
var subprocsAllowed int
|
||||
var subprocsAllowedCond *sync.Cond = sync.NewCond(&sync.Mutex{})
|
||||
|
||||
// Current subprocesses being executed
|
||||
var subprocsRunning int
|
||||
|
||||
// Wakeup on a free subprocess slot.
|
||||
var subprocsRunningCond *sync.Cond = sync.NewCond(&sync.Mutex{})
|
||||
|
||||
// Prevent more than one recipe at a time from trying to take over
|
||||
var exclusiveSubproc = sync.Mutex{}
|
||||
|
||||
// Wait until there is an available subprocess slot.
|
||||
func reserveSubproc() {
|
||||
subprocsAllowedCond.L.Lock()
|
||||
for subprocsAllowed == 0 {
|
||||
subprocsAllowedCond.Wait()
|
||||
subprocsRunningCond.L.Lock()
|
||||
for subprocsRunning >= subprocsAllowed {
|
||||
subprocsRunningCond.Wait()
|
||||
}
|
||||
subprocsAllowed--
|
||||
subprocsAllowedCond.L.Unlock()
|
||||
subprocsRunning++
|
||||
subprocsRunningCond.L.Unlock()
|
||||
}
|
||||
|
||||
// Free up another subprocess to run.
|
||||
func finishSubproc() {
|
||||
subprocsAllowedCond.L.Lock()
|
||||
subprocsAllowed++
|
||||
subprocsAllowedCond.Signal()
|
||||
subprocsAllowedCond.L.Unlock()
|
||||
subprocsRunningCond.L.Lock()
|
||||
subprocsRunning--
|
||||
subprocsRunningCond.Signal()
|
||||
subprocsRunningCond.L.Unlock()
|
||||
}
|
||||
|
||||
// Make everyone wait while we
|
||||
func reserveExclusiveSubproc() {
|
||||
exclusiveSubproc.Lock()
|
||||
// Wait until everything is done running
|
||||
stolen_subprocs := 0
|
||||
subprocsRunningCond.L.Lock()
|
||||
stolen_subprocs = subprocsAllowed - subprocsRunning
|
||||
subprocsRunning = subprocsAllowed
|
||||
for stolen_subprocs < subprocsAllowed {
|
||||
subprocsRunningCond.Wait()
|
||||
stolen_subprocs += subprocsAllowed - subprocsRunning
|
||||
subprocsRunning = subprocsAllowed
|
||||
}
|
||||
}
|
||||
|
||||
func finishExclusiveSubproc() {
|
||||
subprocsRunning = 0
|
||||
subprocsRunningCond.Broadcast()
|
||||
subprocsRunningCond.L.Unlock()
|
||||
exclusiveSubproc.Unlock()
|
||||
}
|
||||
|
||||
// Ansi color codes.
|
||||
|
|
@ -161,12 +191,22 @@ func mkNode(g *graph, u *node, dryrun bool) {
|
|||
|
||||
// execute the recipe, unless the prereqs failed
|
||||
if !uptodate && finalstatus != nodeStatusFailed && len(e.r.recipe) > 0 {
|
||||
reserveSubproc()
|
||||
if e.r.attributes.exclusive {
|
||||
reserveExclusiveSubproc()
|
||||
} else {
|
||||
reserveSubproc()
|
||||
}
|
||||
|
||||
if !dorecipe(u.name, u, e, dryrun) {
|
||||
finalstatus = nodeStatusFailed
|
||||
}
|
||||
u.updateTimestamp()
|
||||
finishSubproc()
|
||||
|
||||
if e.r.attributes.exclusive {
|
||||
finishExclusiveSubproc()
|
||||
} else {
|
||||
finishSubproc()
|
||||
}
|
||||
} else if finalstatus != nodeStatusFailed {
|
||||
finalstatus = nodeStatusNop
|
||||
}
|
||||
|
|
@ -267,7 +307,7 @@ func main() {
|
|||
// Create a dummy virtula rule that depends on every target
|
||||
root := rule{}
|
||||
root.targets = []pattern{pattern{false, "", nil}}
|
||||
root.attributes = attribSet{false, false, false, false, false, false, false, true}
|
||||
root.attributes = attribSet{false, false, false, false, false, false, false, true, false}
|
||||
root.prereqs = targets
|
||||
rs.add(root)
|
||||
|
||||
|
|
|
|||
2
parse.go
2
parse.go
|
|
@ -328,7 +328,7 @@ func parseRecipe(p *parser, t token) parserStateFun {
|
|||
patstr := fmt.Sprintf("^%s(.*)%s$", left, right)
|
||||
rpat, err := regexp.Compile(patstr)
|
||||
if err != nil {
|
||||
msg := fmt.Sprintf("error compiling suffix rule. This is a bug.", err)
|
||||
msg := fmt.Sprintf("error compiling suffix rule. This is a bug. Error: %s", err)
|
||||
p.basicErrorAtToken(msg, p.tokenbuf[k])
|
||||
}
|
||||
r.targets[len(r.targets)-1].rpat = rpat
|
||||
|
|
|
|||
3
rules.go
3
rules.go
|
|
@ -20,6 +20,7 @@ type attribSet struct {
|
|||
regex bool // regular expression meta-rule
|
||||
update bool // treat the targets as if they were updated
|
||||
virtual bool // rule is virtual (does not match files)
|
||||
exclusive bool // don't execute concurrently with any other rule
|
||||
}
|
||||
|
||||
// Error parsing an attribute
|
||||
|
|
@ -113,6 +114,8 @@ func (r *rule) parseAttribs(inputs []string) *attribError {
|
|||
r.attributes.update = true
|
||||
case 'V':
|
||||
r.attributes.virtual = true
|
||||
case 'X':
|
||||
r.attributes.exclusive = true
|
||||
case 'P':
|
||||
if pos+w < len(input) {
|
||||
r.command = append(r.command, input[pos+w:])
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue