github.com/c12o16h1/go/src@v0.0.0-20200114212001-5a151c0f00ed/runtime/internal/atomic/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  // +build arm
     6  
     7  package atomic
     8  
     9  import (
    10  	"github.com/c12o16h1/go/src/internal/cpu"
    11  	"unsafe"
    12  )
    13  
    14  // Export some functions via linkname to assembly in sync/atomic.
    15  //go:linkname Xchg
    16  //go:linkname Xchguintptr
    17  
    18  type spinlock struct {
    19  	v uint32
    20  }
    21  
    22  //go:nosplit
    23  func (l *spinlock) lock() {
    24  	for {
    25  		if Cas(&l.v, 0, 1) {
    26  			return
    27  		}
    28  	}
    29  }
    30  
    31  //go:nosplit
    32  func (l *spinlock) unlock() {
    33  	Store(&l.v, 0)
    34  }
    35  
    36  var locktab [57]struct {
    37  	l   spinlock
    38  	pad [cpu.CacheLinePadSize - unsafe.Sizeof(spinlock{})]byte
    39  }
    40  
    41  func addrLock(addr *uint64) *spinlock {
    42  	return &locktab[(uintptr(unsafe.Pointer(addr))>>3)%uintptr(len(locktab))].l
    43  }
    44  
    45  // Atomic add and return new value.
    46  //go:nosplit
    47  func Xadd(val *uint32, delta int32) uint32 {
    48  	for {
    49  		oval := *val
    50  		nval := oval + uint32(delta)
    51  		if Cas(val, oval, nval) {
    52  			return nval
    53  		}
    54  	}
    55  }
    56  
    57  //go:noescape
    58  func Xadduintptr(ptr *uintptr, delta uintptr) uintptr
    59  
    60  //go:nosplit
    61  func Xchg(addr *uint32, v uint32) uint32 {
    62  	for {
    63  		old := *addr
    64  		if Cas(addr, old, v) {
    65  			return old
    66  		}
    67  	}
    68  }
    69  
    70  //go:nosplit
    71  func Xchguintptr(addr *uintptr, v uintptr) uintptr {
    72  	return uintptr(Xchg((*uint32)(unsafe.Pointer(addr)), uint32(v)))
    73  }
    74  
    75  // Not noescape -- it installs a pointer to addr.
    76  func StorepNoWB(addr unsafe.Pointer, v unsafe.Pointer)
    77  
    78  //go:noescape
    79  func Store(addr *uint32, v uint32)
    80  
    81  //go:noescape
    82  func StoreRel(addr *uint32, v uint32)
    83  
    84  //go:nosplit
    85  func goCas64(addr *uint64, old, new uint64) bool {
    86  	if uintptr(unsafe.Pointer(addr))&7 != 0 {
    87  		*(*int)(nil) = 0 // crash on unaligned uint64
    88  	}
    89  	_ = *addr // if nil, fault before taking the lock
    90  	var ok bool
    91  	addrLock(addr).lock()
    92  	if *addr == old {
    93  		*addr = new
    94  		ok = true
    95  	}
    96  	addrLock(addr).unlock()
    97  	return ok
    98  }
    99  
   100  //go:nosplit
   101  func goXadd64(addr *uint64, delta int64) uint64 {
   102  	if uintptr(unsafe.Pointer(addr))&7 != 0 {
   103  		*(*int)(nil) = 0 // crash on unaligned uint64
   104  	}
   105  	_ = *addr // if nil, fault before taking the lock
   106  	var r uint64
   107  	addrLock(addr).lock()
   108  	r = *addr + uint64(delta)
   109  	*addr = r
   110  	addrLock(addr).unlock()
   111  	return r
   112  }
   113  
   114  //go:nosplit
   115  func goXchg64(addr *uint64, v uint64) uint64 {
   116  	if uintptr(unsafe.Pointer(addr))&7 != 0 {
   117  		*(*int)(nil) = 0 // crash on unaligned uint64
   118  	}
   119  	_ = *addr // if nil, fault before taking the lock
   120  	var r uint64
   121  	addrLock(addr).lock()
   122  	r = *addr
   123  	*addr = v
   124  	addrLock(addr).unlock()
   125  	return r
   126  }
   127  
   128  //go:nosplit
   129  func goLoad64(addr *uint64) uint64 {
   130  	if uintptr(unsafe.Pointer(addr))&7 != 0 {
   131  		*(*int)(nil) = 0 // crash on unaligned uint64
   132  	}
   133  	_ = *addr // if nil, fault before taking the lock
   134  	var r uint64
   135  	addrLock(addr).lock()
   136  	r = *addr
   137  	addrLock(addr).unlock()
   138  	return r
   139  }
   140  
   141  //go:nosplit
   142  func goStore64(addr *uint64, v uint64) {
   143  	if uintptr(unsafe.Pointer(addr))&7 != 0 {
   144  		*(*int)(nil) = 0 // crash on unaligned uint64
   145  	}
   146  	_ = *addr // if nil, fault before taking the lock
   147  	addrLock(addr).lock()
   148  	*addr = v
   149  	addrLock(addr).unlock()
   150  }
   151  
   152  //go:nosplit
   153  func Or8(addr *uint8, v uint8) {
   154  	// Align down to 4 bytes and use 32-bit CAS.
   155  	uaddr := uintptr(unsafe.Pointer(addr))
   156  	addr32 := (*uint32)(unsafe.Pointer(uaddr &^ 3))
   157  	word := uint32(v) << ((uaddr & 3) * 8) // little endian
   158  	for {
   159  		old := *addr32
   160  		if Cas(addr32, old, old|word) {
   161  			return
   162  		}
   163  	}
   164  }
   165  
   166  //go:nosplit
   167  func And8(addr *uint8, v uint8) {
   168  	// Align down to 4 bytes and use 32-bit CAS.
   169  	uaddr := uintptr(unsafe.Pointer(addr))
   170  	addr32 := (*uint32)(unsafe.Pointer(uaddr &^ 3))
   171  	word := uint32(v) << ((uaddr & 3) * 8)    // little endian
   172  	mask := uint32(0xFF) << ((uaddr & 3) * 8) // little endian
   173  	word |= ^mask
   174  	for {
   175  		old := *addr32
   176  		if Cas(addr32, old, old&word) {
   177  			return
   178  		}
   179  	}
   180  }
   181  
   182  //go:nosplit
   183  func armcas(ptr *uint32, old, new uint32) bool
   184  
   185  //go:noescape
   186  func Load(addr *uint32) uint32
   187  
   188  // NO go:noescape annotation; *addr escapes if result escapes (#31525)
   189  func Loadp(addr unsafe.Pointer) unsafe.Pointer
   190  
   191  //go:noescape
   192  func Load8(addr *uint8) uint8
   193  
   194  //go:noescape
   195  func LoadAcq(addr *uint32) uint32
   196  
   197  //go:noescape
   198  func Cas64(addr *uint64, old, new uint64) bool
   199  
   200  //go:noescape
   201  func CasRel(addr *uint32, old, new uint32) bool
   202  
   203  //go:noescape
   204  func Xadd64(addr *uint64, delta int64) uint64
   205  
   206  //go:noescape
   207  func Xchg64(addr *uint64, v uint64) uint64
   208  
   209  //go:noescape
   210  func Load64(addr *uint64) uint64
   211  
   212  //go:noescape
   213  func Store8(addr *uint8, v uint8)
   214  
   215  //go:noescape
   216  func Store64(addr *uint64, v uint64)