Source file src/internal/runtime/atomic/types.go
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