| // 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) |
| } |