// Copyright 2011 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 race_test
import (
"runtime"
"sync"
"sync/atomic"
"testing"
"unsafe"
)
func TestNoRaceAtomicAddInt64(t *testing.T) {
var x1, x2 int8
var s int64
ch := make(chan bool, 2)
go func() {
x1 = 1
if atomic.AddInt64(&s, 1) == 2 {
x2 = 1
}
ch <- true
}()
go func() {
x2 = 1
if atomic.AddInt64(&s, 1) == 2 {
x1 = 1
}
ch <- true
}()
<-ch
<-ch
}
func TestRaceAtomicAddInt64(t *testing.T) {
var x1, x2 int8
var s int64
ch := make(chan bool, 2)
go func() {
x1 = 1
if atomic.AddInt64(&s, 1) == 1 {
x2 = 1
}
ch <- true
}()
go func() {
x2 = 1
if atomic.AddInt64(&s, 1) == 1 {
x1 = 1
}
ch <- true
}()
<-ch
<-ch
}
func TestNoRaceAtomicAddInt32(t *testing.T) {
var x1, x2 int8
var s int32
ch := make(chan bool, 2)
go func() {
x1 = 1
if atomic.AddInt32(&s, 1) == 2 {
x2 = 1
}
ch <- true
}()
go func() {
x2 = 1
if atomic.AddInt32(&s, 1) == 2 {
x1 = 1
}
ch <- true
}()
<-ch
<-ch
}
func TestNoRaceAtomicLoadAddInt32(t *testing.T) {
var x int64
var s int32
go func() {
x = 2
atomic.AddInt32(&s, 1)
}()
for atomic.LoadInt32(&s) != 1 {
runtime.Gosched()
}
x = 1
}
func TestNoRaceAtomicLoadStoreInt32(t *testing.T) {
var x int64
var s int32
go func() {
x = 2
atomic.StoreInt32(&s, 1)
}()
for atomic.LoadInt32(&s) != 1 {
runtime.Gosched()
}
x = 1
}
func TestNoRaceAtomicStoreCASInt32(t *testing.T) {
var x int64
var s int32
go func() {
x = 2
atomic.StoreInt32(&s, 1)
}()
for !atomic.CompareAndSwapInt32(&s, 1, 0) {
runtime.Gosched()
}
x = 1
}
func TestNoRaceAtomicCASLoadInt32(t *testing.T) {
var x int64
var s int32
go func() {
x = 2
if !atomic.CompareAndSwapInt32(&s, 0, 1) {
panic("")
}
}()
for atomic.LoadInt32(&s) != 1 {
runtime.Gosched()
}
x = 1
}
func TestNoRaceAtomicCASCASInt32(t *testing.T) {
var x int64
var s int32
go func() {
x = 2
if !atomic.CompareAndSwapInt32(&s, 0, 1) {
panic("")
}
}()
for !atomic.CompareAndSwapInt32(&s, 1, 0) {
runtime.Gosched()
}
x = 1
}
func TestNoRaceAtomicCASCASInt32_2(t *testing.T) {
var x1, x2 int8
var s int32
ch := make(chan bool, 2)
go func() {
x1 = 1
if !atomic.CompareAndSwapInt32(&s, 0, 1) {
x2 = 1
}
ch <- true
}()
go func() {
x2 = 1
if !atomic.CompareAndSwapInt32(&s, 0, 1) {
x1 = 1
}
ch <- true
}()
<-ch
<-ch
}
func TestNoRaceAtomicLoadInt64(t *testing.T) {
var x int32
var s int64
go func() {
x = 2
atomic.AddInt64(&s, 1)
}()
for atomic.LoadInt64(&s) != 1 {
runtime.Gosched()
}
x = 1
}
func TestNoRaceAtomicCASCASUInt64(t *testing.T) {
var x int64
var s uint64
go func() {
x = 2
if !atomic.CompareAndSwapUint64(&s, 0, 1) {
panic("")
}
}()
for !atomic.CompareAndSwapUint64(&s, 1, 0) {
runtime.Gosched()
}
x = 1
}
func TestNoRaceAtomicLoadStorePointer(t *testing.T) {
var x int64
var s unsafe.Pointer
var y int = 2
var p unsafe.Pointer = unsafe.Pointer(&y)
go func() {
x = 2
atomic.StorePointer(&s, p)
}()
for atomic.LoadPointer(&s) != p {
runtime.Gosched()
}
x = 1
}
func TestNoRaceAtomicStoreCASUint64(t *testing.T) {
var x int64
var s uint64
go func() {
x = 2
atomic.StoreUint64(&s, 1)
}()
for !atomic.CompareAndSwapUint64(&s, 1, 0) {
runtime.Gosched()
}
x = 1
}
func TestRaceAtomicStoreLoad(t *testing.T) {
c := make(chan bool)
var a uint64
go func() {
atomic.StoreUint64(&a, 1)
c <- true
}()
_ = a
<-c
}
func TestRaceAtomicLoadStore(t *testing.T) {
c := make(chan bool)
var a uint64
go func() {
_ = atomic.LoadUint64(&a)
c <- true
}()
a = 1
<-c
}
func TestRaceAtomicAddLoad(t *testing.T) {
c := make(chan bool)
var a uint64
go func() {
atomic.AddUint64(&a, 1)
c <- true
}()
_ = a
<-c
}
func TestRaceAtomicAddStore(t *testing.T) {
c := make(chan bool)
var a uint64
go func() {
atomic.AddUint64(&a, 1)
c <- true
}()
a = 42
<-c
}
// A nil pointer in an atomic operation should not deadlock
// the rest of the program. Used to hang indefinitely.
func TestNoRaceAtomicCrash(t *testing.T) {
var mutex sync.Mutex
var nilptr *int32
panics := 0
defer func() {
if x := recover(); x != nil {
mutex.Lock()
panics++
mutex.Unlock()
} else {
panic("no panic")
}
}()
atomic.AddInt32(nilptr, 1)
}