From 721716ca1cfac23787aa3c722a8eecd9a0d5b296 Mon Sep 17 00:00:00 2001 From: Cherry Zhang Date: Fri, 27 Mar 2020 16:32:22 -0400 Subject: [PATCH] [dev.link] cmd/link: set attributes atomically Now concurrent relocsym may access symbols attributes concurrently, causing data race when using the race detector. I think it is still safe as we read/write on different bits, and not write the same symbol's attributes from multiple goroutines, so it will always reads the right value regardless whether the write happens before or after, as long as the memory model is not so insane. Use atomic accesses to appease the race detector. It doesn't seem to cost much, at least on x86. Change-Id: I2bfc3755ee59c87ed237d508f29d6172fa976392 Reviewed-on: https://go-review.googlesource.com/c/go/+/226368 Reviewed-by: Austin Clements --- src/cmd/link/internal/sym/attribute.go | 60 +++++++++++++++----------- 1 file changed, 36 insertions(+), 24 deletions(-) diff --git a/src/cmd/link/internal/sym/attribute.go b/src/cmd/link/internal/sym/attribute.go index 4b69bf32d0..eda3fe60e4 100644 --- a/src/cmd/link/internal/sym/attribute.go +++ b/src/cmd/link/internal/sym/attribute.go @@ -4,6 +4,8 @@ package sym +import "sync/atomic" + // Attribute is a set of common symbol attributes. type Attribute int32 @@ -84,34 +86,44 @@ const ( // 19 attributes defined so far. ) -func (a Attribute) DuplicateOK() bool { return a&AttrDuplicateOK != 0 } -func (a Attribute) External() bool { return a&AttrExternal != 0 } -func (a Attribute) NoSplit() bool { return a&AttrNoSplit != 0 } -func (a Attribute) Reachable() bool { return a&AttrReachable != 0 } -func (a Attribute) CgoExportDynamic() bool { return a&AttrCgoExportDynamic != 0 } -func (a Attribute) CgoExportStatic() bool { return a&AttrCgoExportStatic != 0 } -func (a Attribute) Special() bool { return a&AttrSpecial != 0 } -func (a Attribute) StackCheck() bool { return a&AttrStackCheck != 0 } -func (a Attribute) NotInSymbolTable() bool { return a&AttrNotInSymbolTable != 0 } -func (a Attribute) OnList() bool { return a&AttrOnList != 0 } -func (a Attribute) Local() bool { return a&AttrLocal != 0 } -func (a Attribute) ReflectMethod() bool { return a&AttrReflectMethod != 0 } -func (a Attribute) MakeTypelink() bool { return a&AttrMakeTypelink != 0 } -func (a Attribute) Shared() bool { return a&AttrShared != 0 } -func (a Attribute) VisibilityHidden() bool { return a&AttrVisibilityHidden != 0 } -func (a Attribute) SubSymbol() bool { return a&AttrSubSymbol != 0 } -func (a Attribute) Container() bool { return a&AttrContainer != 0 } -func (a Attribute) TopFrame() bool { return a&AttrTopFrame != 0 } -func (a Attribute) ReadOnly() bool { return a&AttrReadOnly != 0 } +func (a *Attribute) load() Attribute { return Attribute(atomic.LoadInt32((*int32)(a))) } + +func (a *Attribute) DuplicateOK() bool { return a.load()&AttrDuplicateOK != 0 } +func (a *Attribute) External() bool { return a.load()&AttrExternal != 0 } +func (a *Attribute) NoSplit() bool { return a.load()&AttrNoSplit != 0 } +func (a *Attribute) Reachable() bool { return a.load()&AttrReachable != 0 } +func (a *Attribute) CgoExportDynamic() bool { return a.load()&AttrCgoExportDynamic != 0 } +func (a *Attribute) CgoExportStatic() bool { return a.load()&AttrCgoExportStatic != 0 } +func (a *Attribute) Special() bool { return a.load()&AttrSpecial != 0 } +func (a *Attribute) StackCheck() bool { return a.load()&AttrStackCheck != 0 } +func (a *Attribute) NotInSymbolTable() bool { return a.load()&AttrNotInSymbolTable != 0 } +func (a *Attribute) OnList() bool { return a.load()&AttrOnList != 0 } +func (a *Attribute) Local() bool { return a.load()&AttrLocal != 0 } +func (a *Attribute) ReflectMethod() bool { return a.load()&AttrReflectMethod != 0 } +func (a *Attribute) MakeTypelink() bool { return a.load()&AttrMakeTypelink != 0 } +func (a *Attribute) Shared() bool { return a.load()&AttrShared != 0 } +func (a *Attribute) VisibilityHidden() bool { return a.load()&AttrVisibilityHidden != 0 } +func (a *Attribute) SubSymbol() bool { return a.load()&AttrSubSymbol != 0 } +func (a *Attribute) Container() bool { return a.load()&AttrContainer != 0 } +func (a *Attribute) TopFrame() bool { return a.load()&AttrTopFrame != 0 } +func (a *Attribute) ReadOnly() bool { return a.load()&AttrReadOnly != 0 } -func (a Attribute) CgoExport() bool { +func (a *Attribute) CgoExport() bool { return a.CgoExportDynamic() || a.CgoExportStatic() } func (a *Attribute) Set(flag Attribute, value bool) { - if value { - *a |= flag - } else { - *a &^= flag + // XXX it would be nice if we have atomic And, Or. + for { + a0 := a.load() + var anew Attribute + if value { + anew = a0 | flag + } else { + anew = a0 &^ flag + } + if atomic.CompareAndSwapInt32((*int32)(a), int32(a0), int32(anew)) { + return + } } } -- 2.50.0