Fix data race when applying replacements
Mutator context goroutines appending directly to the global Context's replacements list causes a data race. Send them over a channel instead. The renames and replacements are local to the mutator, so move them out of Context and into the runMutator method. Change-Id: I797edb1e27ee29f8946c58101b40fcfb50a32eb9
This commit is contained in:
parent
0f1fa92e86
commit
0ce142ca05
2 changed files with 49 additions and 32 deletions
68
context.go
68
context.go
|
@ -101,10 +101,6 @@ type Context struct {
|
||||||
// set lazily by sortedModuleNames
|
// set lazily by sortedModuleNames
|
||||||
cachedSortedModuleNames []string
|
cachedSortedModuleNames []string
|
||||||
|
|
||||||
// List of pending renames and replacements to apply after the mutator pass
|
|
||||||
renames []rename
|
|
||||||
replacements []replace
|
|
||||||
|
|
||||||
globs map[string]GlobPath
|
globs map[string]GlobPath
|
||||||
globLock sync.Mutex
|
globLock sync.Mutex
|
||||||
|
|
||||||
|
@ -1706,16 +1702,22 @@ func (c *Context) runMutator(config interface{}, mutator *mutatorInfo,
|
||||||
newModuleInfo[k] = v
|
newModuleInfo[k] = v
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type globalStateChange struct {
|
||||||
|
reverse []reverseDep
|
||||||
|
rename []rename
|
||||||
|
replace []replace
|
||||||
|
}
|
||||||
|
|
||||||
reverseDeps := make(map[*moduleInfo][]depInfo)
|
reverseDeps := make(map[*moduleInfo][]depInfo)
|
||||||
|
var rename []rename
|
||||||
|
var replace []replace
|
||||||
|
|
||||||
errsCh := make(chan []error)
|
errsCh := make(chan []error)
|
||||||
reverseDepsCh := make(chan []reverseDep)
|
globalStateCh := make(chan globalStateChange)
|
||||||
newModulesCh := make(chan []*moduleInfo)
|
newModulesCh := make(chan []*moduleInfo)
|
||||||
done := make(chan bool)
|
done := make(chan bool)
|
||||||
|
|
||||||
c.depsModified = 0
|
c.depsModified = 0
|
||||||
c.renames = nil
|
|
||||||
c.replacements = nil
|
|
||||||
|
|
||||||
visit := func(module *moduleInfo) bool {
|
visit := func(module *moduleInfo) bool {
|
||||||
if module.splitModules != nil {
|
if module.splitModules != nil {
|
||||||
|
@ -1755,8 +1757,12 @@ func (c *Context) runMutator(config interface{}, mutator *mutatorInfo,
|
||||||
newModulesCh <- mctx.newModules
|
newModulesCh <- mctx.newModules
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(mctx.reverseDeps) > 0 {
|
if len(mctx.reverseDeps) > 0 || len(mctx.replace) > 0 || len(mctx.rename) > 0 {
|
||||||
reverseDepsCh <- mctx.reverseDeps
|
globalStateCh <- globalStateChange{
|
||||||
|
reverse: mctx.reverseDeps,
|
||||||
|
replace: mctx.replace,
|
||||||
|
rename: mctx.rename,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
return false
|
||||||
|
@ -1768,10 +1774,12 @@ func (c *Context) runMutator(config interface{}, mutator *mutatorInfo,
|
||||||
select {
|
select {
|
||||||
case newErrs := <-errsCh:
|
case newErrs := <-errsCh:
|
||||||
errs = append(errs, newErrs...)
|
errs = append(errs, newErrs...)
|
||||||
case newReverseDeps := <-reverseDepsCh:
|
case globalStateChange := <-globalStateCh:
|
||||||
for _, r := range newReverseDeps {
|
for _, r := range globalStateChange.reverse {
|
||||||
reverseDeps[r.module] = append(reverseDeps[r.module], r.dep)
|
reverseDeps[r.module] = append(reverseDeps[r.module], r.dep)
|
||||||
}
|
}
|
||||||
|
replace = append(replace, globalStateChange.replace...)
|
||||||
|
rename = append(rename, globalStateChange.rename...)
|
||||||
case newModules := <-newModulesCh:
|
case newModules := <-newModulesCh:
|
||||||
for _, m := range newModules {
|
for _, m := range newModules {
|
||||||
newModuleInfo[m.logicModule] = m
|
newModuleInfo[m.logicModule] = m
|
||||||
|
@ -1821,7 +1829,12 @@ func (c *Context) runMutator(config interface{}, mutator *mutatorInfo,
|
||||||
c.depsModified++
|
c.depsModified++
|
||||||
}
|
}
|
||||||
|
|
||||||
errs = c.handleRenamesAndReplacements()
|
errs = c.handleRenames(rename)
|
||||||
|
if len(errs) > 0 {
|
||||||
|
return errs
|
||||||
|
}
|
||||||
|
|
||||||
|
errs = c.handleReplacements(replace)
|
||||||
if len(errs) > 0 {
|
if len(errs) > 0 {
|
||||||
return errs
|
return errs
|
||||||
}
|
}
|
||||||
|
@ -2124,36 +2137,25 @@ type rename struct {
|
||||||
name string
|
name string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Context) rename(group *moduleGroup, name string) {
|
func (c *Context) moduleMatchingVariant(module *moduleInfo, name string) *moduleInfo {
|
||||||
c.renames = append(c.renames, rename{group, name})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Context) replaceDependencies(module *moduleInfo, name string) {
|
|
||||||
targets := c.modulesFromName(name)
|
targets := c.modulesFromName(name)
|
||||||
|
|
||||||
if targets == nil {
|
if targets == nil {
|
||||||
panic(fmt.Errorf("ReplaceDependencies called with non-existant name %q", name))
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var target *moduleInfo
|
|
||||||
for _, m := range targets {
|
for _, m := range targets {
|
||||||
if module.variantName == m.variantName {
|
if module.variantName == m.variantName {
|
||||||
target = m
|
return m
|
||||||
break
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if target == nil {
|
return nil
|
||||||
panic(fmt.Errorf("ReplaceDependencies could not find identical variant %q for module %q",
|
|
||||||
module.variantName, name))
|
|
||||||
}
|
|
||||||
|
|
||||||
c.replacements = append(c.replacements, replace{target, module})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Context) handleRenamesAndReplacements() []error {
|
func (c *Context) handleRenames(renames []rename) []error {
|
||||||
var errs []error
|
var errs []error
|
||||||
for _, rename := range c.renames {
|
for _, rename := range renames {
|
||||||
group, name := rename.group, rename.name
|
group, name := rename.group, rename.name
|
||||||
if name == group.name {
|
if name == group.name {
|
||||||
continue
|
continue
|
||||||
|
@ -2180,7 +2182,12 @@ func (c *Context) handleRenamesAndReplacements() []error {
|
||||||
group.name = name
|
group.name = name
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, replace := range c.replacements {
|
return errs
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Context) handleReplacements(replacements []replace) []error {
|
||||||
|
var errs []error
|
||||||
|
for _, replace := range replacements {
|
||||||
for _, m := range replace.from.reverseDeps {
|
for _, m := range replace.from.reverseDeps {
|
||||||
for i, d := range m.directDeps {
|
for i, d := range m.directDeps {
|
||||||
if d.module == replace.from {
|
if d.module == replace.from {
|
||||||
|
@ -2191,6 +2198,7 @@ func (c *Context) handleRenamesAndReplacements() []error {
|
||||||
|
|
||||||
atomic.AddUint32(&c.depsModified, 1)
|
atomic.AddUint32(&c.depsModified, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
return errs
|
return errs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -461,6 +461,8 @@ type mutatorContext struct {
|
||||||
baseModuleContext
|
baseModuleContext
|
||||||
name string
|
name string
|
||||||
reverseDeps []reverseDep
|
reverseDeps []reverseDep
|
||||||
|
rename []rename
|
||||||
|
replace []replace
|
||||||
newModules []*moduleInfo
|
newModules []*moduleInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -669,7 +671,14 @@ func (mctx *mutatorContext) AddInterVariantDependency(tag DependencyTag, from, t
|
||||||
// specified name with the current variant of this module. Replacements don't take effect until
|
// specified name with the current variant of this module. Replacements don't take effect until
|
||||||
// after the mutator pass is finished.
|
// after the mutator pass is finished.
|
||||||
func (mctx *mutatorContext) ReplaceDependencies(name string) {
|
func (mctx *mutatorContext) ReplaceDependencies(name string) {
|
||||||
mctx.context.replaceDependencies(mctx.module, name)
|
target := mctx.context.moduleMatchingVariant(mctx.module, name)
|
||||||
|
|
||||||
|
if target == nil {
|
||||||
|
panic(fmt.Errorf("ReplaceDependencies could not find identical variant %q for module %q",
|
||||||
|
mctx.module.variantName, name))
|
||||||
|
}
|
||||||
|
|
||||||
|
mctx.replace = append(mctx.replace, replace{target, mctx.module})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mctx *mutatorContext) OtherModuleExists(name string) bool {
|
func (mctx *mutatorContext) OtherModuleExists(name string) bool {
|
||||||
|
@ -679,7 +688,7 @@ func (mctx *mutatorContext) OtherModuleExists(name string) bool {
|
||||||
// Rename all variants of a module. The new name is not visible to calls to ModuleName,
|
// Rename all variants of a module. The new name is not visible to calls to ModuleName,
|
||||||
// AddDependency or OtherModuleName until after this mutator pass is complete.
|
// AddDependency or OtherModuleName until after this mutator pass is complete.
|
||||||
func (mctx *mutatorContext) Rename(name string) {
|
func (mctx *mutatorContext) Rename(name string) {
|
||||||
mctx.context.rename(mctx.module.group, name)
|
mctx.rename = append(mctx.rename, rename{mctx.module.group, name})
|
||||||
}
|
}
|
||||||
|
|
||||||
// SimpleName is an embeddable object to implement the ModuleContext.Name method using a property
|
// SimpleName is an embeddable object to implement the ModuleContext.Name method using a property
|
||||||
|
|
Loading…
Reference in a new issue