...

Source file src/internal/runtime/atomic/types.go

Documentation: internal/runtime/atomic

     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  

View as plain text