]> Cypherpunks repositories - gostls13.git/commitdiff
sync/atomic: public And/Or ops and race instrumentation
authorMauri de Souza Meneguzzo <mauri870@gmail.com>
Thu, 16 May 2024 22:12:47 +0000 (22:12 +0000)
committerGopher Robot <gobot@golang.org>
Fri, 17 May 2024 18:37:29 +0000 (18:37 +0000)
This CL implements the new sync/atomic AND and OR apis as well as their race
counterparts.

Fixes #61395

Change-Id: I294eefe4b3ac27bc4ed237edcbfa88a8c646d86f
GitHub-Last-Rev: f174297007c7b81b1ff4a687ef23d955a3ffd4db
GitHub-Pull-Request: golang/go#64331
Reviewed-on: https://go-review.googlesource.com/c/go/+/544455
Reviewed-by: Keith Randall <khr@golang.org>
Reviewed-by: Austin Clements <austin@google.com>
Auto-Submit: Austin Clements <austin@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Keith Randall <khr@google.com>
api/next/61395.txt [new file with mode: 0644]
doc/next/6-stdlib/99-minor/sync/atomic/61395.md [new file with mode: 0644]
src/runtime/race.go
src/runtime/race_amd64.s
src/runtime/race_arm64.s
src/runtime/race_ppc64le.s
src/runtime/race_s390x.s
src/sync/atomic/asm.s
src/sync/atomic/atomic_test.go
src/sync/atomic/doc.go
src/sync/atomic/type.go

diff --git a/api/next/61395.txt b/api/next/61395.txt
new file mode 100644 (file)
index 0000000..0efca67
--- /dev/null
@@ -0,0 +1,20 @@
+pkg sync/atomic, func AndInt32(*int32, int32) int32 #61395
+pkg sync/atomic, func AndInt64(*int64, int64) int64 #61395
+pkg sync/atomic, func AndUint32(*uint32, uint32) uint32 #61395
+pkg sync/atomic, func AndUint64(*uint64, uint64) uint64 #61395
+pkg sync/atomic, func AndUintptr(*uintptr, uintptr) uintptr #61395
+pkg sync/atomic, func OrInt32(*int32, int32) int32 #61395
+pkg sync/atomic, func OrInt64(*int64, int64) int64 #61395
+pkg sync/atomic, func OrUint32(*uint32, uint32) uint32 #61395
+pkg sync/atomic, func OrUint64(*uint64, uint64) uint64 #61395
+pkg sync/atomic, func OrUintptr(*uintptr, uintptr) uintptr #61395
+pkg sync/atomic, method (*Int32) And(int32) int32 #61395
+pkg sync/atomic, method (*Int64) And(int64) int64 #61395
+pkg sync/atomic, method (*Uint32) And(uint32) uint32 #61395
+pkg sync/atomic, method (*Uint64) And(uint64) uint64 #61395
+pkg sync/atomic, method (*Uintptr) And(uintptr) uintptr #61395
+pkg sync/atomic, method (*Int32) Or(int32) int32 #61395
+pkg sync/atomic, method (*Int64) Or(int64) int64 #61395
+pkg sync/atomic, method (*Uint32) Or(uint32) uint32 #61395
+pkg sync/atomic, method (*Uint64) Or(uint64) uint64 #61395
+pkg sync/atomic, method (*Uintptr) Or(uintptr) uintptr #61395
diff --git a/doc/next/6-stdlib/99-minor/sync/atomic/61395.md b/doc/next/6-stdlib/99-minor/sync/atomic/61395.md
new file mode 100644 (file)
index 0000000..0535934
--- /dev/null
@@ -0,0 +1,3 @@
+<!-- Issue #61395 -->
+The new [`atomic.And`](/pkg/sync/atomic#And) and [`atomic.Or`](/pkg/sync/atomic#Or)
+operators apply a bitwise `AND` or `OR` to the given input, returning the old value.
index 9acc0c692003ef90517f634c29e8fae35dedf1f6..7d5cbce49ee20d3e765da4540ba873a3442b56b2 100644 (file)
@@ -323,6 +323,10 @@ var __tsan_report_count byte
 //go:cgo_import_static __tsan_go_atomic64_exchange
 //go:cgo_import_static __tsan_go_atomic32_fetch_add
 //go:cgo_import_static __tsan_go_atomic64_fetch_add
+//go:cgo_import_static __tsan_go_atomic32_fetch_and
+//go:cgo_import_static __tsan_go_atomic64_fetch_and
+//go:cgo_import_static __tsan_go_atomic32_fetch_or
+//go:cgo_import_static __tsan_go_atomic64_fetch_or
 //go:cgo_import_static __tsan_go_atomic32_compare_exchange
 //go:cgo_import_static __tsan_go_atomic64_compare_exchange
 
@@ -642,6 +646,36 @@ func abigen_sync_atomic_AddUint64(addr *uint64, delta uint64) (new uint64)
 //go:linkname abigen_sync_atomic_AddUintptr sync/atomic.AddUintptr
 func abigen_sync_atomic_AddUintptr(addr *uintptr, delta uintptr) (new uintptr)
 
+//go:linkname abigen_sync_atomic_AndInt32 sync/atomic.AndInt32
+func abigen_sync_atomic_AndInt32(addr *int32, mask int32) (old int32)
+
+//go:linkname abigen_sync_atomic_AndUint32 sync/atomic.AndUint32
+func abigen_sync_atomic_AndUint32(addr *uint32, mask uint32) (old uint32)
+
+//go:linkname abigen_sync_atomic_AndInt64 sync/atomic.AndInt64
+func abigen_sync_atomic_AndInt64(addr *int64, mask int64) (old int64)
+
+//go:linkname abigen_sync_atomic_AndUint64 sync/atomic.AndUint64
+func abigen_sync_atomic_AndUint64(addr *uint64, mask uint64) (old uint64)
+
+//go:linkname abigen_sync_atomic_AndUintptr sync/atomic.AndUintptr
+func abigen_sync_atomic_AndUintptr(addr *uintptr, mask uintptr) (old uintptr)
+
+//go:linkname abigen_sync_atomic_OrInt32 sync/atomic.OrInt32
+func abigen_sync_atomic_OrInt32(addr *int32, mask int32) (old int32)
+
+//go:linkname abigen_sync_atomic_OrUint32 sync/atomic.OrUint32
+func abigen_sync_atomic_OrUint32(addr *uint32, mask uint32) (old uint32)
+
+//go:linkname abigen_sync_atomic_OrInt64 sync/atomic.OrInt64
+func abigen_sync_atomic_OrInt64(addr *int64, mask int64) (old int64)
+
+//go:linkname abigen_sync_atomic_OrUint64 sync/atomic.OrUint64
+func abigen_sync_atomic_OrUint64(addr *uint64, mask uint64) (old uint64)
+
+//go:linkname abigen_sync_atomic_OrUintptr sync/atomic.OrUintptr
+func abigen_sync_atomic_OrUintptr(addr *uintptr, mask uintptr) (old uintptr)
+
 //go:linkname abigen_sync_atomic_CompareAndSwapInt32 sync/atomic.CompareAndSwapInt32
 func abigen_sync_atomic_CompareAndSwapInt32(addr *int32, old, new int32) (swapped bool)
 
index 45c1255509c8fbaf8bc953959302268c75701393..c4a6d493162c35b95febd92accdb18ab64e1d639 100644 (file)
@@ -303,6 +303,57 @@ TEXT       sync∕atomic·AddUintptr(SB), NOSPLIT, $0-24
        GO_ARGS
        JMP     sync∕atomic·AddInt64(SB)
 
+// And
+TEXT   sync∕atomic·AndInt32(SB), NOSPLIT|NOFRAME, $0-20
+       GO_ARGS
+       MOVQ    $__tsan_go_atomic32_fetch_and(SB), AX
+       CALL    racecallatomic<>(SB)
+       RET
+
+TEXT   sync∕atomic·AndInt64(SB), NOSPLIT|NOFRAME, $0-24
+       GO_ARGS
+       MOVQ    $__tsan_go_atomic64_fetch_and(SB), AX
+       CALL    racecallatomic<>(SB)
+       RET
+
+TEXT   sync∕atomic·AndUint32(SB), NOSPLIT, $0-20
+       GO_ARGS
+       JMP     sync∕atomic·AndInt32(SB)
+
+TEXT   sync∕atomic·AndUint64(SB), NOSPLIT, $0-24
+       GO_ARGS
+       JMP     sync∕atomic·AndInt64(SB)
+
+TEXT   sync∕atomic·AndUintptr(SB), NOSPLIT, $0-24
+       GO_ARGS
+       JMP     sync∕atomic·AndInt64(SB)
+
+// Or
+TEXT   sync∕atomic·OrInt32(SB), NOSPLIT|NOFRAME, $0-20
+       GO_ARGS
+       MOVQ    $__tsan_go_atomic32_fetch_or(SB), AX
+       CALL    racecallatomic<>(SB)
+       RET
+
+TEXT   sync∕atomic·OrInt64(SB), NOSPLIT|NOFRAME, $0-24
+       GO_ARGS
+       MOVQ    $__tsan_go_atomic64_fetch_or(SB), AX
+       CALL    racecallatomic<>(SB)
+       RET
+
+TEXT   sync∕atomic·OrUint32(SB), NOSPLIT, $0-20
+       GO_ARGS
+       JMP     sync∕atomic·OrInt32(SB)
+
+TEXT   sync∕atomic·OrUint64(SB), NOSPLIT, $0-24
+       GO_ARGS
+       JMP     sync∕atomic·OrInt64(SB)
+
+TEXT   sync∕atomic·OrUintptr(SB), NOSPLIT, $0-24
+       GO_ARGS
+       JMP     sync∕atomic·OrInt64(SB)
+
+
 // CompareAndSwap
 TEXT   sync∕atomic·CompareAndSwapInt32(SB), NOSPLIT|NOFRAME, $0-17
        GO_ARGS
index ae0030cf105f5efd19d78ba894d6227e95dd29fb..c42a6c1377528ea621ed709b160ab26432552b9f 100644 (file)
@@ -312,6 +312,56 @@ TEXT       sync∕atomic·AddUintptr(SB), NOSPLIT, $0-24
        GO_ARGS
        JMP     sync∕atomic·AddInt64(SB)
 
+// And
+TEXT   sync∕atomic·AndInt32(SB), NOSPLIT, $0-20
+       GO_ARGS
+       MOVD    $__tsan_go_atomic32_fetch_and(SB), R9
+       BL      racecallatomic<>(SB)
+       RET
+
+TEXT   sync∕atomic·AndInt64(SB), NOSPLIT, $0-24
+       GO_ARGS
+       MOVD    $__tsan_go_atomic64_fetch_and(SB), R9
+       BL      racecallatomic<>(SB)
+       RET
+
+TEXT   sync∕atomic·AndUint32(SB), NOSPLIT, $0-20
+       GO_ARGS
+       JMP     sync∕atomic·AndInt32(SB)
+
+TEXT   sync∕atomic·AndUint64(SB), NOSPLIT, $0-24
+       GO_ARGS
+       JMP     sync∕atomic·AndInt64(SB)
+
+TEXT   sync∕atomic·AndUintptr(SB), NOSPLIT, $0-24
+       GO_ARGS
+       JMP     sync∕atomic·AndInt64(SB)
+
+// Or
+TEXT   sync∕atomic·OrInt32(SB), NOSPLIT, $0-20
+       GO_ARGS
+       MOVD    $__tsan_go_atomic32_fetch_or(SB), R9
+       BL      racecallatomic<>(SB)
+       RET
+
+TEXT   sync∕atomic·OrInt64(SB), NOSPLIT, $0-24
+       GO_ARGS
+       MOVD    $__tsan_go_atomic64_fetch_or(SB), R9
+       BL      racecallatomic<>(SB)
+       RET
+
+TEXT   sync∕atomic·OrUint32(SB), NOSPLIT, $0-20
+       GO_ARGS
+       JMP     sync∕atomic·OrInt32(SB)
+
+TEXT   sync∕atomic·OrUint64(SB), NOSPLIT, $0-24
+       GO_ARGS
+       JMP     sync∕atomic·OrInt64(SB)
+
+TEXT   sync∕atomic·OrUintptr(SB), NOSPLIT, $0-24
+       GO_ARGS
+       JMP     sync∕atomic·OrInt64(SB)
+
 // CompareAndSwap
 TEXT   sync∕atomic·CompareAndSwapInt32(SB), NOSPLIT, $0-17
        GO_ARGS
index 39cfffc39bbeb7fd89321a60d5f73ec5245f6d41..43829479bde86841f889b673bfa1086a5e45ee22 100644 (file)
@@ -325,6 +325,52 @@ TEXT       sync∕atomic·AddUintptr(SB), NOSPLIT, $0-24
        GO_ARGS
        BR      sync∕atomic·AddInt64(SB)
 
+// And
+TEXT   sync∕atomic·AndInt32(SB), NOSPLIT, $0-20
+       GO_ARGS
+       MOVD    $__tsan_go_atomic32_fetch_and(SB), R8
+       BR      racecallatomic<>(SB)
+
+TEXT   sync∕atomic·AndInt64(SB), NOSPLIT, $0-24
+       GO_ARGS
+       MOVD    $__tsan_go_atomic64_fetch_and(SB), R8
+       BR      racecallatomic<>(SB)
+
+TEXT   sync∕atomic·AndUint32(SB), NOSPLIT, $0-20
+       GO_ARGS
+       BR      sync∕atomic·AndInt32(SB)
+
+TEXT   sync∕atomic·AndUint64(SB), NOSPLIT, $0-24
+       GO_ARGS
+       BR      sync∕atomic·AndInt64(SB)
+
+TEXT   sync∕atomic·AndUintptr(SB), NOSPLIT, $0-24
+       GO_ARGS
+       BR      sync∕atomic·AndInt64(SB)
+
+// Or
+TEXT   sync∕atomic·OrInt32(SB), NOSPLIT, $0-20
+       GO_ARGS
+       MOVD    $__tsan_go_atomic32_fetch_or(SB), R8
+       BR      racecallatomic<>(SB)
+
+TEXT   sync∕atomic·OrInt64(SB), NOSPLIT, $0-24
+       GO_ARGS
+       MOVD    $__tsan_go_atomic64_fetch_or(SB), R8
+       BR      racecallatomic<>(SB)
+
+TEXT   sync∕atomic·OrUint32(SB), NOSPLIT, $0-20
+       GO_ARGS
+       BR      sync∕atomic·OrInt32(SB)
+
+TEXT   sync∕atomic·OrUint64(SB), NOSPLIT, $0-24
+       GO_ARGS
+       BR      sync∕atomic·OrInt64(SB)
+
+TEXT   sync∕atomic·OrUintptr(SB), NOSPLIT, $0-24
+       GO_ARGS
+       BR      sync∕atomic·OrInt64(SB)
+
 // CompareAndSwap in tsan
 TEXT   sync∕atomic·CompareAndSwapInt32(SB), NOSPLIT, $0-17
        GO_ARGS
index dadc12f4dbfba5a28c5fac8b731dc8d7f1cf0ac3..8e6a5d576ab4ce65163c2c2be84782749219169b 100644 (file)
@@ -274,6 +274,56 @@ TEXT       sync∕atomic·AddUintptr(SB), NOSPLIT, $0-24
        GO_ARGS
        JMP     sync∕atomic·AddInt64(SB)
 
+// And
+TEXT   sync∕atomic·AndInt32(SB), NOSPLIT, $0-20
+       GO_ARGS
+       MOVD    $__tsan_go_atomic32_fetch_and(SB), R1
+       BL      racecallatomic<>(SB)
+       RET
+
+TEXT   sync∕atomic·AndInt64(SB), NOSPLIT, $0-24
+       GO_ARGS
+       MOVD    $__tsan_go_atomic64_fetch_and(SB), R1
+       BL      racecallatomic<>(SB)
+       RET
+
+TEXT   sync∕atomic·AndUint32(SB), NOSPLIT, $0-20
+       GO_ARGS
+       JMP     sync∕atomic·AndInt32(SB)
+
+TEXT   sync∕atomic·AndUint64(SB), NOSPLIT, $0-24
+       GO_ARGS
+       JMP     sync∕atomic·AndInt64(SB)
+
+TEXT   sync∕atomic·AndUintptr(SB), NOSPLIT, $0-24
+       GO_ARGS
+       JMP     sync∕atomic·AndInt64(SB)
+
+// Or
+TEXT   sync∕atomic·OrInt32(SB), NOSPLIT, $0-20
+       GO_ARGS
+       MOVD    $__tsan_go_atomic32_fetch_or(SB), R1
+       BL      racecallatomic<>(SB)
+       RET
+
+TEXT   sync∕atomic·OrInt64(SB), NOSPLIT, $0-24
+       GO_ARGS
+       MOVD    $__tsan_go_atomic64_fetch_or(SB), R1
+       BL      racecallatomic<>(SB)
+       RET
+
+TEXT   sync∕atomic·OrUint32(SB), NOSPLIT, $0-20
+       GO_ARGS
+       JMP     sync∕atomic·OrInt32(SB)
+
+TEXT   sync∕atomic·OrUint64(SB), NOSPLIT, $0-24
+       GO_ARGS
+       JMP     sync∕atomic·OrInt64(SB)
+
+TEXT   sync∕atomic·OrUintptr(SB), NOSPLIT, $0-24
+       GO_ARGS
+       JMP     sync∕atomic·OrInt64(SB)
+
 // CompareAndSwap
 
 TEXT   sync∕atomic·CompareAndSwapInt32(SB), NOSPLIT, $0-17
index b9318fe8b76103e6238305908eb746023e74ccfb..c46869ede7f4460a79a000bcaa3431e583c356c9 100644 (file)
@@ -83,3 +83,33 @@ TEXT ·StoreUint64(SB),NOSPLIT,$0
 
 TEXT ·StoreUintptr(SB),NOSPLIT,$0
        JMP     internal∕runtime∕atomic·Storeuintptr(SB)
+
+TEXT ·AndInt32(SB),NOSPLIT,$0
+       JMP     internal∕runtime∕atomic·And32(SB)
+
+TEXT ·AndUint32(SB),NOSPLIT,$0
+       JMP     internal∕runtime∕atomic·And32(SB)
+
+TEXT ·AndUintptr(SB),NOSPLIT,$0
+       JMP     internal∕runtime∕atomic·Anduintptr(SB)
+
+TEXT ·AndInt64(SB),NOSPLIT,$0
+       JMP     internal∕runtime∕atomic·And64(SB)
+
+TEXT ·AndUint64(SB),NOSPLIT,$0
+       JMP     internal∕runtime∕atomic·And64(SB)
+
+TEXT ·OrInt32(SB),NOSPLIT,$0
+       JMP     internal∕runtime∕atomic·Or32(SB)
+
+TEXT ·OrUint32(SB),NOSPLIT,$0
+       JMP     internal∕runtime∕atomic·Or32(SB)
+
+TEXT ·OrUintptr(SB),NOSPLIT,$0
+       JMP     internal∕runtime∕atomic·Oruintptr(SB)
+
+TEXT ·OrInt64(SB),NOSPLIT,$0
+       JMP     internal∕runtime∕atomic·Or64(SB)
+
+TEXT ·OrUint64(SB),NOSPLIT,$0
+       JMP     internal∕runtime∕atomic·Or64(SB)
index c3604ef0af01d2e3ffa748f4f5f3527072012dd7..0617b27aca83ec2839f8dc8d6583969d3e0eb978 100644 (file)
@@ -531,6 +531,472 @@ func TestAddUintptrMethod(t *testing.T) {
        }
 }
 
+func TestAndInt32(t *testing.T) {
+       var x struct {
+               before int32
+               i      int32
+               after  int32
+       }
+       x.before = magic32
+       x.after = magic32
+       x.i = -1
+       j := x.i
+       for mask := int32(1); mask != 0; mask <<= 1 {
+               old := x.i
+               k := AndInt32(&x.i, ^mask)
+               j &= ^mask
+               if x.i != j || k != old {
+                       t.Fatalf("mask=%d i=%d j=%d k=%d old=%d", mask, x.i, j, k, old)
+               }
+       }
+       if x.before != magic32 || x.after != magic32 {
+               t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic32, magic32)
+       }
+}
+
+func TestAndInt32Method(t *testing.T) {
+       var x struct {
+               before int32
+               i      Int32
+               after  int32
+       }
+       x.before = magic32
+       x.after = magic32
+       x.i.Store(-1)
+       j := x.i.Load()
+       for mask := int32(1); mask != 0; mask <<= 1 {
+               old := x.i.Load()
+               k := x.i.And(^mask)
+               j &= ^mask
+               if x.i.Load() != j || k != old {
+                       t.Fatalf("mask=%d i=%d j=%d k=%d old=%d", mask, x.i.Load(), j, k, old)
+               }
+       }
+       if x.before != magic32 || x.after != magic32 {
+               t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic32, magic32)
+       }
+}
+
+func TestAndUint32(t *testing.T) {
+       var x struct {
+               before uint32
+               i      uint32
+               after  uint32
+       }
+       x.before = magic32
+       x.after = magic32
+       x.i = 0xffffffff
+       j := x.i
+       for mask := uint32(1); mask != 0; mask <<= 1 {
+               old := x.i
+               k := AndUint32(&x.i, ^mask)
+               j &= ^mask
+               if x.i != j || k != old {
+                       t.Fatalf("mask=%d i=%d j=%d k=%d old=%d", mask, x.i, j, k, old)
+               }
+       }
+       if x.before != magic32 || x.after != magic32 {
+               t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic32, magic32)
+       }
+}
+
+func TestAndUint32Method(t *testing.T) {
+       var x struct {
+               before uint32
+               i      Uint32
+               after  uint32
+       }
+       x.before = magic32
+       x.after = magic32
+       x.i.Store(0xffffffff)
+       j := x.i.Load()
+       for mask := uint32(1); mask != 0; mask <<= 1 {
+               old := x.i.Load()
+               k := x.i.And(^mask)
+               j &= ^mask
+               if x.i.Load() != j || k != old {
+                       t.Fatalf("mask=%d i=%d j=%d k=%d old=%d", mask, x.i.Load(), j, k, old)
+               }
+       }
+       if x.before != magic32 || x.after != magic32 {
+               t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic32, magic32)
+       }
+}
+
+func TestAndInt64(t *testing.T) {
+       var x struct {
+               before int64
+               i      int64
+               after  int64
+       }
+       magic64 := int64(magic64)
+       x.before = magic64
+       x.after = magic64
+       x.i = -1
+       j := x.i
+       for mask := int64(1); mask != 0; mask <<= 1 {
+               old := x.i
+               k := AndInt64(&x.i, ^mask)
+               j &= ^mask
+               if x.i != j || k != old {
+                       t.Fatalf("mask=%d i=%d j=%d k=%d old=%d", mask, x.i, j, k, old)
+               }
+       }
+       if x.before != magic64 || x.after != magic64 {
+               t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic64, magic64)
+       }
+}
+
+func TestAndInt64Method(t *testing.T) {
+       var x struct {
+               before int64
+               i      Int64
+               after  int64
+       }
+       magic64 := int64(magic64)
+       x.before = magic64
+       x.after = magic64
+       x.i.Store(-1)
+       j := x.i.Load()
+       for mask := int64(1); mask != 0; mask <<= 1 {
+               old := x.i.Load()
+               k := x.i.And(^mask)
+               j &= ^mask
+               if x.i.Load() != j || k != old {
+                       t.Fatalf("mask=%d i=%d j=%d k=%d old=%d", mask, x.i.Load(), j, k, old)
+               }
+       }
+       if x.before != magic64 || x.after != magic64 {
+               t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic64, magic64)
+       }
+}
+
+func TestAndUint64(t *testing.T) {
+       var x struct {
+               before uint64
+               i      uint64
+               after  uint64
+       }
+       magic64 := uint64(magic64)
+       x.before = magic64
+       x.after = magic64
+       x.i = 0xfffffffffffffff
+       j := x.i
+       for mask := uint64(1); mask != 0; mask <<= 1 {
+               old := x.i
+               k := AndUint64(&x.i, ^mask)
+               j &= ^mask
+               if x.i != j || k != old {
+                       t.Fatalf("mask=%d i=%d j=%d k=%d old=%d", mask, x.i, j, k, old)
+               }
+       }
+       if x.before != magic64 || x.after != magic64 {
+               t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic64, magic64)
+       }
+}
+
+func TestAndUint64Method(t *testing.T) {
+       var x struct {
+               before uint64
+               i      Uint64
+               after  uint64
+       }
+       magic64 := uint64(magic64)
+       x.before = magic64
+       x.after = magic64
+       x.i.Store(0xfffffffffffffff)
+       j := x.i.Load()
+       for mask := uint64(1); mask != 0; mask <<= 1 {
+               old := x.i.Load()
+               k := x.i.And(^mask)
+               j &= ^mask
+               if x.i.Load() != j || k != old {
+                       t.Fatalf("mask=%d i=%d j=%d k=%d old=%d", mask, x.i.Load(), j, k, old)
+               }
+       }
+       if x.before != magic64 || x.after != magic64 {
+               t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic64, magic64)
+       }
+}
+
+func TestAndUintptr(t *testing.T) {
+       var x struct {
+               before uintptr
+               i      uintptr
+               after  uintptr
+       }
+       var m uint64 = magic64
+       magicptr := uintptr(m)
+       x.before = magicptr
+       x.after = magicptr
+       x.i = ^uintptr(0)
+       j := x.i
+       for mask := uintptr(1); mask != 0; mask <<= 1 {
+               old := x.i
+               k := AndUintptr(&x.i, ^mask)
+               j &= ^mask
+               if x.i != j || k != old {
+                       t.Fatalf("mask=%d i=%d j=%d k=%d old=%d", mask, x.i, j, k, old)
+               }
+       }
+       if x.before != magicptr || x.after != magicptr {
+               t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magicptr, magicptr)
+       }
+}
+
+func TestAndUintptrMethod(t *testing.T) {
+       var x struct {
+               before uintptr
+               i      Uintptr
+               after  uintptr
+       }
+       var m uint64 = magic64
+       magicptr := uintptr(m)
+       x.before = magicptr
+       x.after = magicptr
+       x.i.Store(^uintptr(0))
+       j := x.i.Load()
+       for mask := uintptr(1); mask != 0; mask <<= 1 {
+               old := x.i.Load()
+               k := x.i.And(^mask)
+               j &= ^mask
+               if x.i.Load() != j || k != old {
+                       t.Fatalf("mask=%d i=%d j=%d k=%d old=%d", mask, x.i.Load(), j, k, old)
+               }
+       }
+       if x.before != magicptr || x.after != magicptr {
+               t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magicptr, magicptr)
+       }
+}
+
+func TestOrInt32(t *testing.T) {
+       var x struct {
+               before int32
+               i      int32
+               after  int32
+       }
+       x.before = magic32
+       x.after = magic32
+       var j int32
+       for mask := int32(1); mask != 0; mask <<= 1 {
+               old := x.i
+               k := OrInt32(&x.i, mask)
+               j |= mask
+               if x.i != j || k != old {
+                       t.Fatalf("mask=%d i=%d j=%d k=%d old=%d", mask, x.i, j, k, old)
+               }
+       }
+       if x.before != magic32 || x.after != magic32 {
+               t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic32, magic32)
+       }
+}
+
+func TestOrInt32Method(t *testing.T) {
+       var x struct {
+               before int32
+               i      Int32
+               after  int32
+       }
+       x.before = magic32
+       x.after = magic32
+       var j int32
+       for mask := int32(1); mask != 0; mask <<= 1 {
+               old := x.i.Load()
+               k := x.i.Or(mask)
+               j |= mask
+               if x.i.Load() != j || k != old {
+                       t.Fatalf("mask=%d i=%d j=%d k=%d old=%d", mask, x.i.Load(), j, k, old)
+               }
+       }
+       if x.before != magic32 || x.after != magic32 {
+               t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic32, magic32)
+       }
+}
+
+func TestOrUint32(t *testing.T) {
+       var x struct {
+               before uint32
+               i      uint32
+               after  uint32
+       }
+       x.before = magic32
+       x.after = magic32
+       var j uint32
+       for mask := uint32(1); mask != 0; mask <<= 1 {
+               old := x.i
+               k := OrUint32(&x.i, mask)
+               j |= mask
+               if x.i != j || k != old {
+                       t.Fatalf("mask=%d i=%d j=%d k=%d old=%d", mask, x.i, j, k, old)
+               }
+       }
+       if x.before != magic32 || x.after != magic32 {
+               t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic32, magic32)
+       }
+}
+
+func TestOrUint32Method(t *testing.T) {
+       var x struct {
+               before uint32
+               i      Uint32
+               after  uint32
+       }
+       x.before = magic32
+       x.after = magic32
+       var j uint32
+       for mask := uint32(1); mask != 0; mask <<= 1 {
+               old := x.i.Load()
+               k := x.i.Or(mask)
+               j |= mask
+               if x.i.Load() != j || k != old {
+                       t.Fatalf("mask=%d i=%d j=%d k=%d old=%d", mask, x.i.Load(), j, k, old)
+               }
+       }
+       if x.before != magic32 || x.after != magic32 {
+               t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic32, magic32)
+       }
+}
+
+func TestOrInt64(t *testing.T) {
+       var x struct {
+               before int64
+               i      int64
+               after  int64
+       }
+       magic64 := int64(magic64)
+       x.before = magic64
+       x.after = magic64
+       var j int64
+       for mask := int64(1); mask != 0; mask <<= 1 {
+               old := x.i
+               k := OrInt64(&x.i, mask)
+               j |= mask
+               if x.i != j || k != old {
+                       t.Fatalf("mask=%d i=%d j=%d k=%d old=%d", mask, x.i, j, k, old)
+               }
+       }
+       if x.before != magic64 || x.after != magic64 {
+               t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic64, magic64)
+       }
+}
+
+func TestOrInt64Method(t *testing.T) {
+       var x struct {
+               before int64
+               i      Int64
+               after  int64
+       }
+       magic64 := int64(magic64)
+       x.before = magic64
+       x.after = magic64
+       var j int64
+       for mask := int64(1); mask != 0; mask <<= 1 {
+               old := x.i.Load()
+               k := x.i.Or(mask)
+               j |= mask
+               if x.i.Load() != j || k != old {
+                       t.Fatalf("mask=%d i=%d j=%d k=%d old=%d", mask, x.i.Load(), j, k, old)
+               }
+       }
+       if x.before != magic64 || x.after != magic64 {
+               t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic64, magic64)
+       }
+}
+
+func TestOrUint64(t *testing.T) {
+       var x struct {
+               before uint64
+               i      uint64
+               after  uint64
+       }
+       magic64 := uint64(magic64)
+       x.before = magic64
+       x.after = magic64
+       var j uint64
+       for mask := uint64(1); mask != 0; mask <<= 1 {
+               old := x.i
+               k := OrUint64(&x.i, mask)
+               j |= mask
+               if x.i != j || k != old {
+                       t.Fatalf("mask=%d i=%d j=%d k=%d old=%d", mask, x.i, j, k, old)
+               }
+       }
+       if x.before != magic64 || x.after != magic64 {
+               t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic64, magic64)
+       }
+}
+
+func TestOrUint64Method(t *testing.T) {
+       var x struct {
+               before uint64
+               i      Uint64
+               after  uint64
+       }
+       magic64 := uint64(magic64)
+       x.before = magic64
+       x.after = magic64
+       var j uint64
+       for mask := uint64(1); mask != 0; mask <<= 1 {
+               old := x.i.Load()
+               k := x.i.Or(mask)
+               j |= mask
+               if x.i.Load() != j || k != old {
+                       t.Fatalf("mask=%d i=%d j=%d k=%d old=%d", mask, x.i.Load(), j, k, old)
+               }
+       }
+       if x.before != magic64 || x.after != magic64 {
+               t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic64, magic64)
+       }
+}
+
+func TestOrUintptr(t *testing.T) {
+       var x struct {
+               before uintptr
+               i      uintptr
+               after  uintptr
+       }
+       var m uint64 = magic64
+       magicptr := uintptr(m)
+       x.before = magicptr
+       x.after = magicptr
+       var j uintptr
+       for mask := uintptr(1); mask != 0; mask <<= 1 {
+               old := x.i
+               k := OrUintptr(&x.i, mask)
+               j |= mask
+               if x.i != j || k != old {
+                       t.Fatalf("mask=%d i=%d j=%d k=%d old=%d", mask, x.i, j, k, old)
+               }
+       }
+       if x.before != magicptr || x.after != magicptr {
+               t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magicptr, magicptr)
+       }
+}
+
+func TestOrUintptrMethod(t *testing.T) {
+       var x struct {
+               before uintptr
+               i      Uintptr
+               after  uintptr
+       }
+       var m uint64 = magic64
+       magicptr := uintptr(m)
+       x.before = magicptr
+       x.after = magicptr
+       var j uintptr
+       for mask := uintptr(1); mask != 0; mask <<= 1 {
+               old := x.i.Load()
+               k := x.i.Or(mask)
+               j |= mask
+               if x.i.Load() != j || k != old {
+                       t.Fatalf("mask=%d i=%d j=%d k=%d old=%d", mask, x.i.Load(), j, k, old)
+               }
+       }
+       if x.before != magicptr || x.after != magicptr {
+               t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magicptr, magicptr)
+       }
+}
+
 func TestCompareAndSwapInt32(t *testing.T) {
        var x struct {
                before int32
index c22d1159affa96b568de85f63817645627b60143..1f7f9b277e355cbfe1f86c145874183cfc4629d1 100644 (file)
@@ -139,6 +139,56 @@ func AddUint64(addr *uint64, delta uint64) (new uint64)
 // Consider using the more ergonomic and less error-prone [Uintptr.Add] instead.
 func AddUintptr(addr *uintptr, delta uintptr) (new uintptr)
 
+// AndInt32 atomically performs a bitwise AND operation on *addr using the bitmask provided as mask
+// and returns the old value.
+// Consider using the more ergonomic and less error-prone [Int32.And] instead.
+func AndInt32(addr *int32, mask int32) (old int32)
+
+// AndUint32 atomically performs a bitwise AND operation on *addr using the bitmask provided as mask
+// and returns the old value.
+// Consider using the more ergonomic and less error-prone [Uint32.And] instead.
+func AndUint32(addr *uint32, mask uint32) (old uint32)
+
+// AndInt64 atomically performs a bitwise AND operation on *addr using the bitmask provided as mask
+// and returns the old value.
+// Consider using the more ergonomic and less error-prone [Int64.And] instead.
+func AndInt64(addr *int64, mask int64) (old int64)
+
+// AndUint64 atomically performs a bitwise AND operation on *addr using the bitmask provided as mask
+// and returns the old.
+// Consider using the more ergonomic and less error-prone [Uint64.And] instead.
+func AndUint64(addr *uint64, mask uint64) (old uint64)
+
+// AndUintptr atomically performs a bitwise AND operation on *addr using the bitmask provided as mask
+// and returns the old value.
+// Consider using the more ergonomic and less error-prone [Uintptr.And] instead.
+func AndUintptr(addr *uintptr, mask uintptr) (old uintptr)
+
+// OrInt32 atomically performs a bitwise OR operation on *addr using the bitmask provided as mask
+// and returns the old value.
+// Consider using the more ergonomic and less error-prone [Int32.Or] instead.
+func OrInt32(addr *int32, mask int32) (old int32)
+
+// OrUint32 atomically performs a bitwise OR operation on *addr using the bitmask provided as mask
+// and returns the old value.
+// Consider using the more ergonomic and less error-prone [Uint32.Or] instead.
+func OrUint32(addr *uint32, mask uint32) (old uint32)
+
+// OrInt64 atomically performs a bitwise OR operation on *addr using the bitmask provided as mask
+// and returns the old value.
+// Consider using the more ergonomic and less error-prone [Int64.Or] instead.
+func OrInt64(addr *int64, mask int64) (old int64)
+
+// OrUint64 atomically performs a bitwise OR operation on *addr using the bitmask provided as mask
+// and returns the old value.
+// Consider using the more ergonomic and less error-prone [Uint64.Or] instead.
+func OrUint64(addr *uint64, mask uint64) (old uint64)
+
+// OrUintptr atomically performs a bitwise OR operation on *addr using the bitmask provided as mask
+// and returns the old value.
+// Consider using the more ergonomic and less error-prone [Uintptr.Or] instead.
+func OrUintptr(addr *uintptr, mask uintptr) (old uintptr)
+
 // LoadInt32 atomically loads *addr.
 // Consider using the more ergonomic and less error-prone [Int32.Load] instead.
 func LoadInt32(addr *int32) (val int32)
index 179fa93092be71acd2ec35ca13500523bd03f82a..7d2b6805bca85d959e63fe32725877a07b94aa49 100644 (file)
@@ -87,6 +87,14 @@ func (x *Int32) CompareAndSwap(old, new int32) (swapped bool) {
 // Add atomically adds delta to x and returns the new value.
 func (x *Int32) Add(delta int32) (new int32) { return AddInt32(&x.v, delta) }
 
+// And atomically performs a bitwise AND operation on x using the bitmask
+// provided as mask and returns the old value.
+func (x *Int32) And(mask int32) (old int32) { return AndInt32(&x.v, mask) }
+
+// Or atomically performs a bitwise OR operation on x using the bitmask
+// provided as mask and returns the old value.
+func (x *Int32) Or(mask int32) (old int32) { return OrInt32(&x.v, mask) }
+
 // An Int64 is an atomic int64. The zero value is zero.
 type Int64 struct {
        _ noCopy
@@ -111,6 +119,14 @@ func (x *Int64) CompareAndSwap(old, new int64) (swapped bool) {
 // Add atomically adds delta to x and returns the new value.
 func (x *Int64) Add(delta int64) (new int64) { return AddInt64(&x.v, delta) }
 
+// And atomically performs a bitwise AND operation on x using the bitmask
+// provided as mask and returns the old value.
+func (x *Int64) And(mask int64) (old int64) { return AndInt64(&x.v, mask) }
+
+// Or atomically performs a bitwise OR operation on x using the bitmask
+// provided as mask and returns the old value.
+func (x *Int64) Or(mask int64) (old int64) { return OrInt64(&x.v, mask) }
+
 // A Uint32 is an atomic uint32. The zero value is zero.
 type Uint32 struct {
        _ noCopy
@@ -134,6 +150,14 @@ func (x *Uint32) CompareAndSwap(old, new uint32) (swapped bool) {
 // Add atomically adds delta to x and returns the new value.
 func (x *Uint32) Add(delta uint32) (new uint32) { return AddUint32(&x.v, delta) }
 
+// And atomically performs a bitwise AND operation on x using the bitmask
+// provided as mask and returns the old value.
+func (x *Uint32) And(mask uint32) (old uint32) { return AndUint32(&x.v, mask) }
+
+// Or atomically performs a bitwise OR operation on x using the bitmask
+// provided as mask and returns the old value.
+func (x *Uint32) Or(mask uint32) (new uint32) { return OrUint32(&x.v, mask) }
+
 // A Uint64 is an atomic uint64. The zero value is zero.
 type Uint64 struct {
        _ noCopy
@@ -158,6 +182,14 @@ func (x *Uint64) CompareAndSwap(old, new uint64) (swapped bool) {
 // Add atomically adds delta to x and returns the new value.
 func (x *Uint64) Add(delta uint64) (new uint64) { return AddUint64(&x.v, delta) }
 
+// And atomically performs a bitwise AND operation on x using the bitmask
+// provided as mask and returns the old value.
+func (x *Uint64) And(mask uint64) (old uint64) { return AndUint64(&x.v, mask) }
+
+// Or atomically performs a bitwise OR operation on x using the bitmask
+// provided as mask and returns the old value.
+func (x *Uint64) Or(mask uint64) (new uint64) { return OrUint64(&x.v, mask) }
+
 // A Uintptr is an atomic uintptr. The zero value is zero.
 type Uintptr struct {
        _ noCopy
@@ -181,6 +213,14 @@ func (x *Uintptr) CompareAndSwap(old, new uintptr) (swapped bool) {
 // Add atomically adds delta to x and returns the new value.
 func (x *Uintptr) Add(delta uintptr) (new uintptr) { return AddUintptr(&x.v, delta) }
 
+// And atomically performs a bitwise AND operation on x using the bitmask
+// provided as mask and returns the old value.
+func (x *Uintptr) And(mask uintptr) (old uintptr) { return AndUintptr(&x.v, mask) }
+
+// Or atomically performs a bitwise OR operation on x using the bitmask
+// provided as mask and returns the updated value after the OR operation.
+func (x *Uintptr) Or(mask uintptr) (old uintptr) { return OrUintptr(&x.v, mask) }
+
 // noCopy may be added to structs which must not be copied
 // after the first use.
 //