]> Cypherpunks repositories - gostls13.git/commitdiff
[dev.link] cmd/link: set attributes atomically
authorCherry Zhang <cherryyz@google.com>
Fri, 27 Mar 2020 20:32:22 +0000 (16:32 -0400)
committerCherry Zhang <cherryyz@google.com>
Tue, 31 Mar 2020 16:39:23 +0000 (16:39 +0000)
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 <austin@google.com>
src/cmd/link/internal/sym/attribute.go

index 4b69bf32d07f15fbcb288b91c7e60c68c015f2af..eda3fe60e4d232505fd4af65a59f5b8bd07661a7 100644 (file)
@@ -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
+               }
        }
 }