Skip to content

Commit 9247bdd

Browse files
randall77heschi
authored andcommitted
[release-branch.go1.18] sync/atomic: use consistent first-store-in-progress marker
We need to use the same marker everywhere. My CL to rename the marker (CL 241661) and the CL to add more uses of the marker under the old name (CL 241678) weren't coordinated with each other. Fixes #52615 Change-Id: I97023c0769e518491924ef457fe03bf64a2cefa6 Reviewed-on: https://go-review.googlesource.com/c/go/+/403094 Run-TryBot: Keith Randall <[email protected]> Reviewed-by: Ian Lance Taylor <[email protected]> TryBot-Result: Gopher Robot <[email protected]> Reviewed-by: Keith Randall <[email protected]> Reviewed-on: https://go-review.googlesource.com/c/go/+/403198
1 parent 500d75a commit 9247bdd

File tree

2 files changed

+53
-4
lines changed

2 files changed

+53
-4
lines changed

src/sync/atomic/value.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ func (v *Value) Swap(new any) (old any) {
101101
// active spin wait to wait for completion; and so that
102102
// GC does not see the fake type accidentally.
103103
runtime_procPin()
104-
if !CompareAndSwapPointer(&vp.typ, nil, unsafe.Pointer(^uintptr(0))) {
104+
if !CompareAndSwapPointer(&vp.typ, nil, unsafe.Pointer(&firstStoreInProgress)) {
105105
runtime_procUnpin()
106106
continue
107107
}
@@ -111,7 +111,7 @@ func (v *Value) Swap(new any) (old any) {
111111
runtime_procUnpin()
112112
return nil
113113
}
114-
if uintptr(typ) == ^uintptr(0) {
114+
if typ == unsafe.Pointer(&firstStoreInProgress) {
115115
// First store in progress. Wait.
116116
// Since we disable preemption around the first store,
117117
// we can wait with active spinning.
@@ -153,7 +153,7 @@ func (v *Value) CompareAndSwap(old, new any) (swapped bool) {
153153
// active spin wait to wait for completion; and so that
154154
// GC does not see the fake type accidentally.
155155
runtime_procPin()
156-
if !CompareAndSwapPointer(&vp.typ, nil, unsafe.Pointer(^uintptr(0))) {
156+
if !CompareAndSwapPointer(&vp.typ, nil, unsafe.Pointer(&firstStoreInProgress)) {
157157
runtime_procUnpin()
158158
continue
159159
}
@@ -163,7 +163,7 @@ func (v *Value) CompareAndSwap(old, new any) (swapped bool) {
163163
runtime_procUnpin()
164164
return true
165165
}
166-
if uintptr(typ) == ^uintptr(0) {
166+
if typ == unsafe.Pointer(&firstStoreInProgress) {
167167
// First store in progress. Wait.
168168
// Since we disable preemption around the first store,
169169
// we can wait with active spinning.

test/fixedbugs/issue52612.go

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// run
2+
3+
// Copyright 2022 The Go Authors. All rights reserved.
4+
// Use of this source code is governed by a BSD-style
5+
// license that can be found in the LICENSE file.
6+
7+
package main
8+
9+
import (
10+
"sync/atomic"
11+
"unsafe"
12+
)
13+
14+
var one interface{} = 1
15+
16+
type eface struct {
17+
typ unsafe.Pointer
18+
data unsafe.Pointer
19+
}
20+
21+
func f(c chan struct{}) {
22+
var x atomic.Value
23+
24+
go func() {
25+
x.Swap(one) // writing using the old marker
26+
}()
27+
for i := 0; i < 100000; i++ {
28+
v := x.Load() // reading using the new marker
29+
30+
p := (*eface)(unsafe.Pointer(&v)).typ
31+
if uintptr(p) == ^uintptr(0) {
32+
// We read the old marker, which the new reader
33+
// doesn't know is a case where it should retry
34+
// instead of returning it.
35+
panic("bad typ field")
36+
}
37+
}
38+
c <- struct{}{}
39+
}
40+
41+
func main() {
42+
c := make(chan struct{}, 10)
43+
for i := 0; i < 10; i++ {
44+
go f(c)
45+
}
46+
for i := 0; i < 10; i++ {
47+
<-c
48+
}
49+
}

0 commit comments

Comments
 (0)