github.com/tcnksm/go@v0.0.0-20141208075154-439b32936367/src/runtime/atomic_arm.go (about)

     1  // Copyright 2009 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 runtime
     6  
     7  import "unsafe"
     8  
     9  var locktab [57]struct {
    10  	l   mutex
    11  	pad [_CacheLineSize - unsafe.Sizeof(mutex{})]byte
    12  }
    13  
    14  func addrLock(addr *uint64) *mutex {
    15  	return &locktab[(uintptr(unsafe.Pointer(addr))>>3)%uintptr(len(locktab))].l
    16  }
    17  
    18  // Atomic add and return new value.
    19  //go:nosplit
    20  func xadd(val *uint32, delta int32) uint32 {
    21  	for {
    22  		oval := *val
    23  		nval := oval + uint32(delta)
    24  		if cas(val, oval, nval) {
    25  			return nval
    26  		}
    27  	}
    28  }
    29  
    30  //go:nosplit
    31  func xchg(addr *uint32, v uint32) uint32 {
    32  	for {
    33  		old := *addr
    34  		if cas(addr, old, v) {
    35  			return old
    36  		}
    37  	}
    38  }
    39  
    40  //go:nosplit
    41  func xchgp(addr *unsafe.Pointer, v unsafe.Pointer) unsafe.Pointer {
    42  	for {
    43  		old := *addr
    44  		if casp(addr, old, v) {
    45  			return old
    46  		}
    47  	}
    48  }
    49  
    50  //go:nosplit
    51  func xchguintptr(addr *uintptr, v uintptr) uintptr {
    52  	return uintptr(xchg((*uint32)(unsafe.Pointer(addr)), uint32(v)))
    53  }
    54  
    55  //go:nosplit
    56  func atomicload(addr *uint32) uint32 {
    57  	return xadd(addr, 0)
    58  }
    59  
    60  //go:nosplit
    61  func atomicloadp(addr unsafe.Pointer) unsafe.Pointer {
    62  	return unsafe.Pointer(uintptr(xadd((*uint32)(addr), 0)))
    63  }
    64  
    65  //go:nosplit
    66  func atomicstorep(addr unsafe.Pointer, v unsafe.Pointer) {
    67  	for {
    68  		old := *(*unsafe.Pointer)(addr)
    69  		if casp((*unsafe.Pointer)(addr), old, v) {
    70  			return
    71  		}
    72  	}
    73  }
    74  
    75  //go:nosplit
    76  func atomicstore(addr *uint32, v uint32) {
    77  	for {
    78  		old := *addr
    79  		if cas(addr, old, v) {
    80  			return
    81  		}
    82  	}
    83  }
    84  
    85  //go:nosplit
    86  func cas64(addr *uint64, old, new uint64) bool {
    87  	var ok bool
    88  	systemstack(func() {
    89  		lock(addrLock(addr))
    90  		if *addr == old {
    91  			*addr = new
    92  			ok = true
    93  		}
    94  		unlock(addrLock(addr))
    95  	})
    96  	return ok
    97  }
    98  
    99  //go:nosplit
   100  func xadd64(addr *uint64, delta int64) uint64 {
   101  	var r uint64
   102  	systemstack(func() {
   103  		lock(addrLock(addr))
   104  		r = *addr + uint64(delta)
   105  		*addr = r
   106  		unlock(addrLock(addr))
   107  	})
   108  	return r
   109  }
   110  
   111  //go:nosplit
   112  func xchg64(addr *uint64, v uint64) uint64 {
   113  	var r uint64
   114  	systemstack(func() {
   115  		lock(addrLock(addr))
   116  		r = *addr
   117  		*addr = v
   118  		unlock(addrLock(addr))
   119  	})
   120  	return r
   121  }
   122  
   123  //go:nosplit
   124  func atomicload64(addr *uint64) uint64 {
   125  	var r uint64
   126  	systemstack(func() {
   127  		lock(addrLock(addr))
   128  		r = *addr
   129  		unlock(addrLock(addr))
   130  	})
   131  	return r
   132  }
   133  
   134  //go:nosplit
   135  func atomicstore64(addr *uint64, v uint64) {
   136  	systemstack(func() {
   137  		lock(addrLock(addr))
   138  		*addr = v
   139  		unlock(addrLock(addr))
   140  	})
   141  }
   142  
   143  //go:nosplit
   144  func atomicor8(addr *uint8, v uint8) {
   145  	// Align down to 4 bytes and use 32-bit CAS.
   146  	uaddr := uintptr(unsafe.Pointer(addr))
   147  	addr32 := (*uint32)(unsafe.Pointer(uaddr &^ 3))
   148  	word := uint32(v) << ((uaddr & 3) * 8) // little endian
   149  	for {
   150  		old := *addr32
   151  		if cas(addr32, old, old|word) {
   152  			return
   153  		}
   154  	}
   155  }