semaphore: Create a semaphore metaparam

This adds a P/V style semaphore mechanism to the resource graph. This
enables the user to specify a number of "id:count" tags associated with
each resource which will reduce the parallelism of the CheckApply
operation to that maximum count.

This is particularly interesting because (assuming I'm not mistaken) the
implementation is dead-lock free assuming that no individual resource
permanently ever blocks during execution! I don't have a formal proof of
this, but I was able to convince myself on paper that it was the case.

An actual proof that N P/V counting semaphores in a DAG won't ever
dead-lock would be particularly welcome! Hint: the trick is to acquire
them in alphabetical order while respecting the DAG flow. Disclaimer,
this assumes that the lock count is always > 0 of course.
This commit is contained in:
James Shubin
2017-02-26 20:02:36 -05:00
parent 757cb0cf23
commit d8e19cd79a
11 changed files with 442 additions and 3 deletions

View File

@@ -67,6 +67,7 @@ type Main struct {
NoWatch bool // do not update graph on watched graph definition file changes
Noop bool // globally force all resources into no-op mode
Sema int // add a semaphore with this lock count to each resource
Graphviz string // output file for graphviz data
GraphvizFilter string // graphviz filter to use
ConvergedTimeout int // exit after approximately this many seconds in a converged state; -1 to disable
@@ -443,11 +444,17 @@ func (obj *Main) Run() error {
Debug: obj.Flags.Debug,
})
// apply the global noop parameter if requested
if obj.Noop {
for _, m := range newGraph.GraphMetas() {
for _, m := range newGraph.GraphMetas() {
// apply the global noop parameter if requested
if obj.Noop {
m.Noop = obj.Noop
}
// append the semaphore to each resource
if obj.Sema > 0 { // NOTE: size == 0 would block
// a semaphore with an empty id is valid
m.Sema = append(m.Sema, fmt.Sprintf(":%d", obj.Sema))
}
}
// FIXME: make sure we "UnGroup()" any semi-destructive