summaryrefslogtreecommitdiffhomepage
path: root/pkg/atomicbitops/atomic_bitops_common.go
blob: 542ff4e83dfa039fe92d02f00835687ad613ee39 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
// Copyright 2018 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// +build !amd64

package atomicbitops

import (
	"sync/atomic"
)

// AndUint32 atomically applies bitwise and operation to *addr with val.
func AndUint32(addr *uint32, val uint32) {
	for {
		o := atomic.LoadUint32(addr)
		n := o & val
		if atomic.CompareAndSwapUint32(addr, o, n) {
			break
		}
	}
}

// OrUint32 atomically applies bitwise or operation to *addr with val.
func OrUint32(addr *uint32, val uint32) {
	for {
		o := atomic.LoadUint32(addr)
		n := o | val
		if atomic.CompareAndSwapUint32(addr, o, n) {
			break
		}
	}
}

// XorUint32 atomically applies bitwise xor operation to *addr with val.
func XorUint32(addr *uint32, val uint32) {
	for {
		o := atomic.LoadUint32(addr)
		n := o ^ val
		if atomic.CompareAndSwapUint32(addr, o, n) {
			break
		}
	}
}

// CompareAndSwapUint32 is like sync/atomic.CompareAndSwapUint32, but returns
// the value previously stored at addr.
func CompareAndSwapUint32(addr *uint32, old, new uint32) (prev uint32) {
	for {
		prev = atomic.LoadUint32(addr)
		if prev != old {
			return
		}
		if atomic.CompareAndSwapUint32(addr, old, new) {
			return
		}
	}
}

// AndUint64 atomically applies bitwise and operation to *addr with val.
func AndUint64(addr *uint64, val uint64) {
	for {
		o := atomic.LoadUint64(addr)
		n := o & val
		if atomic.CompareAndSwapUint64(addr, o, n) {
			break
		}
	}
}

// OrUint64 atomically applies bitwise or operation to *addr with val.
func OrUint64(addr *uint64, val uint64) {
	for {
		o := atomic.LoadUint64(addr)
		n := o | val
		if atomic.CompareAndSwapUint64(addr, o, n) {
			break
		}
	}
}

// XorUint64 atomically applies bitwise xor operation to *addr with val.
func XorUint64(addr *uint64, val uint64) {
	for {
		o := atomic.LoadUint64(addr)
		n := o ^ val
		if atomic.CompareAndSwapUint64(addr, o, n) {
			break
		}
	}
}

// CompareAndSwapUint64 is like sync/atomic.CompareAndSwapUint64, but returns
// the value previously stored at addr.
func CompareAndSwapUint64(addr *uint64, old, new uint64) (prev uint64) {
	for {
		prev = atomic.LoadUint64(addr)
		if prev != old {
			return
		}
		if atomic.CompareAndSwapUint64(addr, old, new) {
			return
		}
	}
}

// IncUnlessZeroInt32 increments the value stored at the given address and
// returns true; unless the value stored in the pointer is zero, in which case
// it is left unmodified and false is returned.
func IncUnlessZeroInt32(addr *int32) bool {
	for {
		v := atomic.LoadInt32(addr)
		if v == 0 {
			return false
		}

		if atomic.CompareAndSwapInt32(addr, v, v+1) {
			return true
		}
	}
}

// DecUnlessOneInt32 decrements the value stored at the given address and
// returns true; unless the value stored in the pointer is 1, in which case it
// is left unmodified and false is returned.
func DecUnlessOneInt32(addr *int32) bool {
	for {
		v := atomic.LoadInt32(addr)
		if v == 1 {
			return false
		}

		if atomic.CompareAndSwapInt32(addr, v, v-1) {
			return true
		}
	}
}