// active spin wait to wait for completion; and so that
// GC does not see the fake type accidentally.
runtime_procPin()
- if !CompareAndSwapPointer(&vp.typ, nil, unsafe.Pointer(^uintptr(0))) {
+ if !CompareAndSwapPointer(&vp.typ, nil, unsafe.Pointer(&firstStoreInProgress)) {
runtime_procUnpin()
continue
}
runtime_procUnpin()
return nil
}
- if uintptr(typ) == ^uintptr(0) {
+ if typ == unsafe.Pointer(&firstStoreInProgress) {
// First store in progress. Wait.
// Since we disable preemption around the first store,
// we can wait with active spinning.
// active spin wait to wait for completion; and so that
// GC does not see the fake type accidentally.
runtime_procPin()
- if !CompareAndSwapPointer(&vp.typ, nil, unsafe.Pointer(^uintptr(0))) {
+ if !CompareAndSwapPointer(&vp.typ, nil, unsafe.Pointer(&firstStoreInProgress)) {
runtime_procUnpin()
continue
}
runtime_procUnpin()
return true
}
- if uintptr(typ) == ^uintptr(0) {
+ if typ == unsafe.Pointer(&firstStoreInProgress) {
// First store in progress. Wait.
// Since we disable preemption around the first store,
// we can wait with active spinning.
--- /dev/null
+// run
+
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "sync/atomic"
+ "unsafe"
+)
+
+var one interface{} = 1
+
+type eface struct {
+ typ unsafe.Pointer
+ data unsafe.Pointer
+}
+
+func f(c chan struct{}) {
+ var x atomic.Value
+
+ go func() {
+ x.Swap(one) // writing using the old marker
+ }()
+ for i := 0; i < 100000; i++ {
+ v := x.Load() // reading using the new marker
+
+ p := (*eface)(unsafe.Pointer(&v)).typ
+ if uintptr(p) == ^uintptr(0) {
+ // We read the old marker, which the new reader
+ // doesn't know is a case where it should retry
+ // instead of returning it.
+ panic("bad typ field")
+ }
+ }
+ c <- struct{}{}
+}
+
+func main() {
+ c := make(chan struct{}, 10)
+ for i := 0; i < 10; i++ {
+ go f(c)
+ }
+ for i := 0; i < 10; i++ {
+ <-c
+ }
+}