1 // Copyright 2021 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4 5 package atomic
6 7 import "unsafe"
8 9 // Int32 is an atomically accessed int32 value.
10 //
11 // An Int32 must not be copied.
12 type Int32 struct {
13 noCopy noCopy
14 value int32
15 }
16 17 // Load accesses and returns the value atomically.
18 //
19 //go:nosplit
20 func (i *Int32) Load() int32 {
21 return Loadint32(&i.value)
22 }
23 24 // Store updates the value atomically.
25 //
26 //go:nosplit
27 func (i *Int32) Store(value int32) {
28 Storeint32(&i.value, value)
29 }
30 31 // CompareAndSwap atomically compares i's value with old,
32 // and if they're equal, swaps i's value with new.
33 // It reports whether the swap ran.
34 //
35 //go:nosplit
36 func (i *Int32) CompareAndSwap(old, new int32) bool {
37 return Casint32(&i.value, old, new)
38 }
39 40 // Swap replaces i's value with new, returning
41 // i's value before the replacement.
42 //
43 //go:nosplit
44 func (i *Int32) Swap(new int32) int32 {
45 return Xchgint32(&i.value, new)
46 }
47 48 // Add adds delta to i atomically, returning
49 // the new updated value.
50 //
51 // This operation wraps around in the usual
52 // two's-complement way.
53 //
54 //go:nosplit
55 func (i *Int32) Add(delta int32) int32 {
56 return Xaddint32(&i.value, delta)
57 }
58 59 // Int64 is an atomically accessed int64 value.
60 //
61 // 8-byte aligned on all platforms, unlike a regular int64.
62 //
63 // An Int64 must not be copied.
64 type Int64 struct {
65 noCopy noCopy
66 _ align64
67 value int64
68 }
69 70 // Load accesses and returns the value atomically.
71 //
72 //go:nosplit
73 func (i *Int64) Load() int64 {
74 return Loadint64(&i.value)
75 }
76 77 // Store updates the value atomically.
78 //
79 //go:nosplit
80 func (i *Int64) Store(value int64) {
81 Storeint64(&i.value, value)
82 }
83 84 // CompareAndSwap atomically compares i's value with old,
85 // and if they're equal, swaps i's value with new.
86 // It reports whether the swap ran.
87 //
88 //go:nosplit
89 func (i *Int64) CompareAndSwap(old, new int64) bool {
90 return Casint64(&i.value, old, new)
91 }
92 93 // Swap replaces i's value with new, returning
94 // i's value before the replacement.
95 //
96 //go:nosplit
97 func (i *Int64) Swap(new int64) int64 {
98 return Xchgint64(&i.value, new)
99 }
100 101 // Add adds delta to i atomically, returning
102 // the new updated value.
103 //
104 // This operation wraps around in the usual
105 // two's-complement way.
106 //
107 //go:nosplit
108 func (i *Int64) Add(delta int64) int64 {
109 return Xaddint64(&i.value, delta)
110 }
111 112 // Uint8 is an atomically accessed uint8 value.
113 //
114 // A Uint8 must not be copied.
115 type Uint8 struct {
116 noCopy noCopy
117 value uint8
118 }
119 120 // Load accesses and returns the value atomically.
121 //
122 //go:nosplit
123 func (u *Uint8) Load() uint8 {
124 return Load8(&u.value)
125 }
126 127 // Store updates the value atomically.
128 //
129 //go:nosplit
130 func (u *Uint8) Store(value uint8) {
131 Store8(&u.value, value)
132 }
133 134 // And takes value and performs a bit-wise
135 // "and" operation with the value of u, storing
136 // the result into u.
137 //
138 // The full process is performed atomically.
139 //
140 //go:nosplit
141 func (u *Uint8) And(value uint8) {
142 And8(&u.value, value)
143 }
144 145 // Or takes value and performs a bit-wise
146 // "or" operation with the value of u, storing
147 // the result into u.
148 //
149 // The full process is performed atomically.
150 //
151 //go:nosplit
152 func (u *Uint8) Or(value uint8) {
153 Or8(&u.value, value)
154 }
155 156 // Bool is an atomically accessed bool value.
157 //
158 // A Bool must not be copied.
159 type Bool struct {
160 // Inherits noCopy from Uint8.
161 u Uint8
162 }
163 164 // Load accesses and returns the value atomically.
165 //
166 //go:nosplit
167 func (b *Bool) Load() bool {
168 return b.u.Load() != 0
169 }
170 171 // Store updates the value atomically.
172 //
173 //go:nosplit
174 func (b *Bool) Store(value bool) {
175 s := uint8(0)
176 if value {
177 s = 1
178 }
179 b.u.Store(s)
180 }
181 182 // Uint32 is an atomically accessed uint32 value.
183 //
184 // A Uint32 must not be copied.
185 type Uint32 struct {
186 noCopy noCopy
187 value uint32
188 }
189 190 // Load accesses and returns the value atomically.
191 //
192 //go:nosplit
193 func (u *Uint32) Load() uint32 {
194 return Load(&u.value)
195 }
196 197 // LoadAcquire is a partially unsynchronized version
198 // of Load that relaxes ordering constraints. Other threads
199 // may observe operations that precede this operation to
200 // occur after it, but no operation that occurs after it
201 // on this thread can be observed to occur before it.
202 //
203 // WARNING: Use sparingly and with great care.
204 //
205 //go:nosplit
206 func (u *Uint32) LoadAcquire() uint32 {
207 return LoadAcq(&u.value)
208 }
209 210 // Store updates the value atomically.
211 //
212 //go:nosplit
213 func (u *Uint32) Store(value uint32) {
214 Store(&u.value, value)
215 }
216 217 // StoreRelease is a partially unsynchronized version
218 // of Store that relaxes ordering constraints. Other threads
219 // may observe operations that occur after this operation to
220 // precede it, but no operation that precedes it
221 // on this thread can be observed to occur after it.
222 //
223 // WARNING: Use sparingly and with great care.
224 //
225 //go:nosplit
226 func (u *Uint32) StoreRelease(value uint32) {
227 StoreRel(&u.value, value)
228 }
229 230 // CompareAndSwap atomically compares u's value with old,
231 // and if they're equal, swaps u's value with new.
232 // It reports whether the swap ran.
233 //
234 //go:nosplit
235 func (u *Uint32) CompareAndSwap(old, new uint32) bool {
236 return Cas(&u.value, old, new)
237 }
238 239 // CompareAndSwapRelease is a partially unsynchronized version
240 // of Cas that relaxes ordering constraints. Other threads
241 // may observe operations that occur after this operation to
242 // precede it, but no operation that precedes it
243 // on this thread can be observed to occur after it.
244 // It reports whether the swap ran.
245 //
246 // WARNING: Use sparingly and with great care.
247 //
248 //go:nosplit
249 func (u *Uint32) CompareAndSwapRelease(old, new uint32) bool {
250 return CasRel(&u.value, old, new)
251 }
252 253 // Swap replaces u's value with new, returning
254 // u's value before the replacement.
255 //
256 //go:nosplit
257 func (u *Uint32) Swap(value uint32) uint32 {
258 return Xchg(&u.value, value)
259 }
260 261 // And takes value and performs a bit-wise
262 // "and" operation with the value of u, storing
263 // the result into u.
264 //
265 // The full process is performed atomically.
266 //
267 //go:nosplit
268 func (u *Uint32) And(value uint32) {
269 And(&u.value, value)
270 }
271 272 // Or takes value and performs a bit-wise
273 // "or" operation with the value of u, storing
274 // the result into u.
275 //
276 // The full process is performed atomically.
277 //
278 //go:nosplit
279 func (u *Uint32) Or(value uint32) {
280 Or(&u.value, value)
281 }
282 283 // Add adds delta to u atomically, returning
284 // the new updated value.
285 //
286 // This operation wraps around in the usual
287 // two's-complement way.
288 //
289 //go:nosplit
290 func (u *Uint32) Add(delta int32) uint32 {
291 return Xadd(&u.value, delta)
292 }
293 294 // Uint64 is an atomically accessed uint64 value.
295 //
296 // 8-byte aligned on all platforms, unlike a regular uint64.
297 //
298 // A Uint64 must not be copied.
299 type Uint64 struct {
300 noCopy noCopy
301 _ align64
302 value uint64
303 }
304 305 // Load accesses and returns the value atomically.
306 //
307 //go:nosplit
308 func (u *Uint64) Load() uint64 {
309 return Load64(&u.value)
310 }
311 312 // Store updates the value atomically.
313 //
314 //go:nosplit
315 func (u *Uint64) Store(value uint64) {
316 Store64(&u.value, value)
317 }
318 319 // CompareAndSwap atomically compares u's value with old,
320 // and if they're equal, swaps u's value with new.
321 // It reports whether the swap ran.
322 //
323 //go:nosplit
324 func (u *Uint64) CompareAndSwap(old, new uint64) bool {
325 return Cas64(&u.value, old, new)
326 }
327 328 // Swap replaces u's value with new, returning
329 // u's value before the replacement.
330 //
331 //go:nosplit
332 func (u *Uint64) Swap(value uint64) uint64 {
333 return Xchg64(&u.value, value)
334 }
335 336 // Add adds delta to u atomically, returning
337 // the new updated value.
338 //
339 // This operation wraps around in the usual
340 // two's-complement way.
341 //
342 //go:nosplit
343 func (u *Uint64) Add(delta int64) uint64 {
344 return Xadd64(&u.value, delta)
345 }
346 347 // Uintptr is an atomically accessed uintptr value.
348 //
349 // A Uintptr must not be copied.
350 type Uintptr struct {
351 noCopy noCopy
352 value uintptr
353 }
354 355 // Load accesses and returns the value atomically.
356 //
357 //go:nosplit
358 func (u *Uintptr) Load() uintptr {
359 return Loaduintptr(&u.value)
360 }
361 362 // LoadAcquire is a partially unsynchronized version
363 // of Load that relaxes ordering constraints. Other threads
364 // may observe operations that precede this operation to
365 // occur after it, but no operation that occurs after it
366 // on this thread can be observed to occur before it.
367 //
368 // WARNING: Use sparingly and with great care.
369 //
370 //go:nosplit
371 func (u *Uintptr) LoadAcquire() uintptr {
372 return LoadAcquintptr(&u.value)
373 }
374 375 // Store updates the value atomically.
376 //
377 //go:nosplit
378 func (u *Uintptr) Store(value uintptr) {
379 Storeuintptr(&u.value, value)
380 }
381 382 // StoreRelease is a partially unsynchronized version
383 // of Store that relaxes ordering constraints. Other threads
384 // may observe operations that occur after this operation to
385 // precede it, but no operation that precedes it
386 // on this thread can be observed to occur after it.
387 //
388 // WARNING: Use sparingly and with great care.
389 //
390 //go:nosplit
391 func (u *Uintptr) StoreRelease(value uintptr) {
392 StoreReluintptr(&u.value, value)
393 }
394 395 // CompareAndSwap atomically compares u's value with old,
396 // and if they're equal, swaps u's value with new.
397 // It reports whether the swap ran.
398 //
399 //go:nosplit
400 func (u *Uintptr) CompareAndSwap(old, new uintptr) bool {
401 return Casuintptr(&u.value, old, new)
402 }
403 404 // Swap replaces u's value with new, returning
405 // u's value before the replacement.
406 //
407 //go:nosplit
408 func (u *Uintptr) Swap(value uintptr) uintptr {
409 return Xchguintptr(&u.value, value)
410 }
411 412 // Add adds delta to u atomically, returning
413 // the new updated value.
414 //
415 // This operation wraps around in the usual
416 // two's-complement way.
417 //
418 //go:nosplit
419 func (u *Uintptr) Add(delta uintptr) uintptr {
420 return Xadduintptr(&u.value, delta)
421 }
422 423 // Float64 is an atomically accessed float64 value.
424 //
425 // 8-byte aligned on all platforms, unlike a regular float64.
426 //
427 // A Float64 must not be copied.
428 type Float64 struct {
429 // Inherits noCopy and align64 from Uint64.
430 u Uint64
431 }
432 433 // Load accesses and returns the value atomically.
434 //
435 //go:nosplit
436 func (f *Float64) Load() float64 {
437 r := f.u.Load()
438 return *(*float64)(unsafe.Pointer(&r))
439 }
440 441 // Store updates the value atomically.
442 //
443 //go:nosplit
444 func (f *Float64) Store(value float64) {
445 f.u.Store(*(*uint64)(unsafe.Pointer(&value)))
446 }
447 448 // UnsafePointer is an atomically accessed unsafe.Pointer value.
449 //
450 // Note that because of the atomicity guarantees, stores to values
451 // of this type never trigger a write barrier, and the relevant
452 // methods are suffixed with "NoWB" to indicate that explicitly.
453 // As a result, this type should be used carefully, and sparingly,
454 // mostly with values that do not live in the Go heap anyway.
455 //
456 // An UnsafePointer must not be copied.
457 type UnsafePointer struct {
458 noCopy noCopy
459 value unsafe.Pointer
460 }
461 462 // Load accesses and returns the value atomically.
463 //
464 //go:nosplit
465 func (u *UnsafePointer) Load() unsafe.Pointer {
466 return Loadp(unsafe.Pointer(&u.value))
467 }
468 469 // StoreNoWB updates the value atomically.
470 //
471 // WARNING: As the name implies this operation does *not*
472 // perform a write barrier on value, and so this operation may
473 // hide pointers from the GC. Use with care and sparingly.
474 // It is safe to use with values not found in the Go heap.
475 // Prefer Store instead.
476 //
477 //go:nosplit
478 func (u *UnsafePointer) StoreNoWB(value unsafe.Pointer) {
479 StorepNoWB(unsafe.Pointer(&u.value), value)
480 }
481 482 // Store updates the value atomically.
483 func (u *UnsafePointer) Store(value unsafe.Pointer) {
484 storePointer(&u.value, value)
485 }
486 487 // provided by runtime
488 //
489 //go:linkname storePointer
490 func storePointer(ptr *unsafe.Pointer, new unsafe.Pointer)
491 492 // CompareAndSwapNoWB atomically (with respect to other methods)
493 // compares u's value with old, and if they're equal,
494 // swaps u's value with new.
495 // It reports whether the swap ran.
496 //
497 // WARNING: As the name implies this operation does *not*
498 // perform a write barrier on value, and so this operation may
499 // hide pointers from the GC. Use with care and sparingly.
500 // It is safe to use with values not found in the Go heap.
501 // Prefer CompareAndSwap instead.
502 //
503 //go:nosplit
504 func (u *UnsafePointer) CompareAndSwapNoWB(old, new unsafe.Pointer) bool {
505 return Casp1(&u.value, old, new)
506 }
507 508 // CompareAndSwap atomically compares u's value with old,
509 // and if they're equal, swaps u's value with new.
510 // It reports whether the swap ran.
511 func (u *UnsafePointer) CompareAndSwap(old, new unsafe.Pointer) bool {
512 return casPointer(&u.value, old, new)
513 }
514 515 func casPointer(ptr *unsafe.Pointer, old, new unsafe.Pointer) bool
516 517 // Pointer is an atomic pointer of type *T.
518 type Pointer[T any] struct {
519 u UnsafePointer
520 }
521 522 // Load accesses and returns the value atomically.
523 //
524 //go:nosplit
525 func (p *Pointer[T]) Load() *T {
526 return (*T)(p.u.Load())
527 }
528 529 // StoreNoWB updates the value atomically.
530 //
531 // WARNING: As the name implies this operation does *not*
532 // perform a write barrier on value, and so this operation may
533 // hide pointers from the GC. Use with care and sparingly.
534 // It is safe to use with values not found in the Go heap.
535 // Prefer Store instead.
536 //
537 //go:nosplit
538 func (p *Pointer[T]) StoreNoWB(value *T) {
539 p.u.StoreNoWB(unsafe.Pointer(value))
540 }
541 542 // Store updates the value atomically.
543 //
544 //go:nosplit
545 func (p *Pointer[T]) Store(value *T) {
546 p.u.Store(unsafe.Pointer(value))
547 }
548 549 // CompareAndSwapNoWB atomically (with respect to other methods)
550 // compares u's value with old, and if they're equal,
551 // swaps u's value with new.
552 // It reports whether the swap ran.
553 //
554 // WARNING: As the name implies this operation does *not*
555 // perform a write barrier on value, and so this operation may
556 // hide pointers from the GC. Use with care and sparingly.
557 // It is safe to use with values not found in the Go heap.
558 // Prefer CompareAndSwap instead.
559 //
560 //go:nosplit
561 func (p *Pointer[T]) CompareAndSwapNoWB(old, new *T) bool {
562 return p.u.CompareAndSwapNoWB(unsafe.Pointer(old), unsafe.Pointer(new))
563 }
564 565 // CompareAndSwap atomically (with respect to other methods)
566 // compares u's value with old, and if they're equal,
567 // swaps u's value with new.
568 // It reports whether the swap ran.
569 func (p *Pointer[T]) CompareAndSwap(old, new *T) bool {
570 return p.u.CompareAndSwap(unsafe.Pointer(old), unsafe.Pointer(new))
571 }
572 573 // noCopy may be embedded into structs which must not be copied
574 // after the first use.
575 //
576 // See https://golang.org/issues/8005#issuecomment-190753527
577 // for details.
578 type noCopy struct{}
579 580 // Lock is a no-op used by -copylocks checker from `go vet`.
581 func (*noCopy) Lock() {}
582 func (*noCopy) Unlock() {}
583 584 // align64 may be added to structs that must be 64-bit aligned.
585 // This struct is recognized by a special case in the compiler
586 // and will not work if copied to any other package.
587 type align64 struct{}
588