// 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 _ = x1 + x2 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 _ = x1 + x2 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 _ = x1 + x2 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 _ = x 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 _ = x 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 _ = x 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 _ = x 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 _ = x 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 _ = x1 + x2 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 _ = x 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 _ = x 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 _ = x 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 _ = x 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) } func TestNoRaceDeferAtomicStore(t *testing.T) { // Test that when an atomic function is deferred directly, the // GC scans it correctly. See issue 42599. type foo struct { bar int64 } var doFork func(f *foo, depth int) doFork = func(f *foo, depth int) { atomic.StoreInt64(&f.bar, 1) defer atomic.StoreInt64(&f.bar, 0) if depth > 0 { for i := 0; i < 2; i++ { f2 := &foo{} go doFork(f2, depth-1) } } runtime.GC() } f := &foo{} doFork(f, 11) }