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.
|
// Limit the number of recipes executed simultaneously.
|
||||||
var subprocsAllowed int
|
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.
|
// Wait until there is an available subprocess slot.
|
||||||
func reserveSubproc() {
|
func reserveSubproc() {
|
||||||
subprocsAllowedCond.L.Lock()
|
subprocsRunningCond.L.Lock()
|
||||||
for subprocsAllowed == 0 {
|
for subprocsRunning >= subprocsAllowed {
|
||||||
subprocsAllowedCond.Wait()
|
subprocsRunningCond.Wait()
|
||||||
}
|
}
|
||||||
subprocsAllowed--
|
subprocsRunning++
|
||||||
subprocsAllowedCond.L.Unlock()
|
subprocsRunningCond.L.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Free up another subprocess to run.
|
// Free up another subprocess to run.
|
||||||
func finishSubproc() {
|
func finishSubproc() {
|
||||||
subprocsAllowedCond.L.Lock()
|
subprocsRunningCond.L.Lock()
|
||||||
subprocsAllowed++
|
subprocsRunning--
|
||||||
subprocsAllowedCond.Signal()
|
subprocsRunningCond.Signal()
|
||||||
subprocsAllowedCond.L.Unlock()
|
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.
|
// Ansi color codes.
|
||||||
|
|
@ -161,12 +191,22 @@ func mkNode(g *graph, u *node, dryrun bool) {
|
||||||
|
|
||||||
// execute the recipe, unless the prereqs failed
|
// execute the recipe, unless the prereqs failed
|
||||||
if !uptodate && finalstatus != nodeStatusFailed && len(e.r.recipe) > 0 {
|
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) {
|
if !dorecipe(u.name, u, e, dryrun) {
|
||||||
finalstatus = nodeStatusFailed
|
finalstatus = nodeStatusFailed
|
||||||
}
|
}
|
||||||
u.updateTimestamp()
|
u.updateTimestamp()
|
||||||
finishSubproc()
|
|
||||||
|
if e.r.attributes.exclusive {
|
||||||
|
finishExclusiveSubproc()
|
||||||
|
} else {
|
||||||
|
finishSubproc()
|
||||||
|
}
|
||||||
} else if finalstatus != nodeStatusFailed {
|
} else if finalstatus != nodeStatusFailed {
|
||||||
finalstatus = nodeStatusNop
|
finalstatus = nodeStatusNop
|
||||||
}
|
}
|
||||||
|
|
@ -267,7 +307,7 @@ func main() {
|
||||||
// Create a dummy virtula rule that depends on every target
|
// Create a dummy virtula rule that depends on every target
|
||||||
root := rule{}
|
root := rule{}
|
||||||
root.targets = []pattern{pattern{false, "", nil}}
|
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
|
root.prereqs = targets
|
||||||
rs.add(root)
|
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)
|
patstr := fmt.Sprintf("^%s(.*)%s$", left, right)
|
||||||
rpat, err := regexp.Compile(patstr)
|
rpat, err := regexp.Compile(patstr)
|
||||||
if err != nil {
|
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])
|
p.basicErrorAtToken(msg, p.tokenbuf[k])
|
||||||
}
|
}
|
||||||
r.targets[len(r.targets)-1].rpat = rpat
|
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
|
regex bool // regular expression meta-rule
|
||||||
update bool // treat the targets as if they were updated
|
update bool // treat the targets as if they were updated
|
||||||
virtual bool // rule is virtual (does not match files)
|
virtual bool // rule is virtual (does not match files)
|
||||||
|
exclusive bool // don't execute concurrently with any other rule
|
||||||
}
|
}
|
||||||
|
|
||||||
// Error parsing an attribute
|
// Error parsing an attribute
|
||||||
|
|
@ -113,6 +114,8 @@ func (r *rule) parseAttribs(inputs []string) *attribError {
|
||||||
r.attributes.update = true
|
r.attributes.update = true
|
||||||
case 'V':
|
case 'V':
|
||||||
r.attributes.virtual = true
|
r.attributes.virtual = true
|
||||||
|
case 'X':
|
||||||
|
r.attributes.exclusive = true
|
||||||
case 'P':
|
case 'P':
|
||||||
if pos+w < len(input) {
|
if pos+w < len(input) {
|
||||||
r.command = append(r.command, input[pos+w:])
|
r.command = append(r.command, input[pos+w:])
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue