Skip to content

Commit

Permalink
runtime/internal/atomic: add tests for And8 and Or8
Browse files Browse the repository at this point in the history
Add some simple unit tests for these atomic operations. These can't
catch all the bugs that are possible with these operations but at
least they provide some coverage.

Change-Id: I94b9f451fcc9fecdb2a1448c5357b019563ad275
Reviewed-on: https://go-review.googlesource.com/c/go/+/204317
Run-TryBot: Michael Munday <mike.munday@ibm.com>
Reviewed-by: Austin Clements <austin@google.com>
  • Loading branch information
mundaym committed Oct 31, 2019
1 parent 6becb03 commit 1085560
Showing 1 changed file with 117 additions and 0 deletions.
117 changes: 117 additions & 0 deletions src/runtime/internal/atomic/atomic_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,3 +103,120 @@ func TestUnaligned64(t *testing.T) {
shouldPanic(t, "Xchg64", func() { atomic.Xchg64(up64, 1) })
shouldPanic(t, "Cas64", func() { atomic.Cas64(up64, 1, 2) })
}

func TestAnd8(t *testing.T) {
// Basic sanity check.
x := uint8(0xff)
for i := uint8(0); i < 8; i++ {
atomic.And8(&x, ^(1 << i))
if r := uint8(0xff) << (i + 1); x != r {
t.Fatalf("clearing bit %#x: want %#x, got %#x", uint8(1<<i), r, x)
}
}

// Set every bit in array to 1.
a := make([]uint8, 1<<12)
for i := range a {
a[i] = 0xff
}

// Clear array bit-by-bit in different goroutines.
done := make(chan bool)
for i := 0; i < 8; i++ {
m := ^uint8(1 << i)
go func() {
for i := range a {
atomic.And8(&a[i], m)
}
done <- true
}()
}
for i := 0; i < 8; i++ {
<-done
}

// Check that the array has been totally cleared.
for i, v := range a {
if v != 0 {
t.Fatalf("a[%v] not cleared: want %#x, got %#x", i, uint8(0), v)
}
}
}

func TestOr8(t *testing.T) {
// Basic sanity check.
x := uint8(0)
for i := uint8(0); i < 8; i++ {
atomic.Or8(&x, 1<<i)
if r := (uint8(1) << (i + 1)) - 1; x != r {
t.Fatalf("setting bit %#x: want %#x, got %#x", uint8(1)<<i, r, x)
}
}

// Start with every bit in array set to 0.
a := make([]uint8, 1<<12)

// Set every bit in array bit-by-bit in different goroutines.
done := make(chan bool)
for i := 0; i < 8; i++ {
m := uint8(1 << i)
go func() {
for i := range a {
atomic.Or8(&a[i], m)
}
done <- true
}()
}
for i := 0; i < 8; i++ {
<-done
}

// Check that the array has been totally set.
for i, v := range a {
if v != 0xff {
t.Fatalf("a[%v] not fully set: want %#x, got %#x", i, uint8(0xff), v)
}
}
}

func TestBitwiseContended(t *testing.T) {
// Start with every bit in array set to 0.
a := make([]uint8, 16)

// Iterations to try.
N := 1 << 16
if testing.Short() {
N = 1 << 10
}

// Set and then clear every bit in the array bit-by-bit in different goroutines.
done := make(chan bool)
for i := 0; i < 8; i++ {
m := uint8(1 << i)
go func() {
for n := 0; n < N; n++ {
for i := range a {
atomic.Or8(&a[i], m)
if atomic.Load8(&a[i])&m != m {
t.Errorf("a[%v] bit %#x not set", i, m)
}
atomic.And8(&a[i], ^m)
if atomic.Load8(&a[i])&m != 0 {
t.Errorf("a[%v] bit %#x not clear", i, m)
}
}
}
done <- true
}()
}
for i := 0; i < 8; i++ {
<-done
}

// Check that the array has been totally cleared.
for i, v := range a {
if v != 0 {
t.Fatalf("a[%v] not cleared: want %#x, got %#x", i, uint8(0), v)
}
}
}

0 comments on commit 1085560

Please sign in to comment.