mirror of
https://github.com/golang/go
synced 2024-11-14 15:00:27 -07:00
6ad33be2d9
The motivation is that sysAlloc/Free() currently aren't safe to be called without a valid G, because arm's xadd64() uses locks that require a valid G. The solution here was proposed by Dmitry Vyukov: use xadduintptr() instead of xadd64(), until arm can support xadd64 on all of its architectures (not a trivial task for arm). Change-Id: I250252079357ea2e4360e1235958b1c22051498f Reviewed-on: https://go-review.googlesource.com/9002 Reviewed-by: Dmitry Vyukov <dvyukov@google.com>
175 lines
3.9 KiB
Go
175 lines
3.9 KiB
Go
// Copyright 2010 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package runtime
|
|
|
|
import "unsafe"
|
|
|
|
const memDebug = false
|
|
|
|
var bloc uintptr
|
|
var memlock mutex
|
|
|
|
type memHdr struct {
|
|
next *memHdr
|
|
size uintptr
|
|
}
|
|
|
|
var memFreelist *memHdr // sorted in ascending order
|
|
|
|
func memAlloc(n uintptr) unsafe.Pointer {
|
|
n = memRound(n)
|
|
var prevp *memHdr
|
|
for p := memFreelist; p != nil; p = p.next {
|
|
if p.size >= n {
|
|
if p.size == n {
|
|
if prevp != nil {
|
|
prevp.next = p.next
|
|
} else {
|
|
memFreelist = p.next
|
|
}
|
|
} else {
|
|
p.size -= n
|
|
p = (*memHdr)(add(unsafe.Pointer(p), p.size))
|
|
}
|
|
memclr(unsafe.Pointer(p), unsafe.Sizeof(memHdr{}))
|
|
return unsafe.Pointer(p)
|
|
}
|
|
prevp = p
|
|
}
|
|
return sbrk(n)
|
|
}
|
|
|
|
func memFree(ap unsafe.Pointer, n uintptr) {
|
|
n = memRound(n)
|
|
memclr(ap, n)
|
|
bp := (*memHdr)(ap)
|
|
bp.size = n
|
|
bpn := uintptr(ap)
|
|
if memFreelist == nil {
|
|
bp.next = nil
|
|
memFreelist = bp
|
|
return
|
|
}
|
|
p := memFreelist
|
|
if bpn < uintptr(unsafe.Pointer(p)) {
|
|
memFreelist = bp
|
|
if bpn+bp.size == uintptr(unsafe.Pointer(p)) {
|
|
bp.size += p.size
|
|
bp.next = p.next
|
|
memclr(unsafe.Pointer(p), unsafe.Sizeof(memHdr{}))
|
|
} else {
|
|
bp.next = p
|
|
}
|
|
return
|
|
}
|
|
for ; p.next != nil; p = p.next {
|
|
if bpn > uintptr(unsafe.Pointer(p)) && bpn < uintptr(unsafe.Pointer(p.next)) {
|
|
break
|
|
}
|
|
}
|
|
if bpn+bp.size == uintptr(unsafe.Pointer(p.next)) {
|
|
bp.size += p.next.size
|
|
bp.next = p.next.next
|
|
memclr(unsafe.Pointer(p.next), unsafe.Sizeof(memHdr{}))
|
|
} else {
|
|
bp.next = p.next
|
|
}
|
|
if uintptr(unsafe.Pointer(p))+p.size == bpn {
|
|
p.size += bp.size
|
|
p.next = bp.next
|
|
memclr(unsafe.Pointer(bp), unsafe.Sizeof(memHdr{}))
|
|
} else {
|
|
p.next = bp
|
|
}
|
|
}
|
|
|
|
func memCheck() {
|
|
if memDebug == false {
|
|
return
|
|
}
|
|
for p := memFreelist; p != nil && p.next != nil; p = p.next {
|
|
if uintptr(unsafe.Pointer(p)) == uintptr(unsafe.Pointer(p.next)) {
|
|
print("runtime: ", unsafe.Pointer(p), " == ", unsafe.Pointer(p.next), "\n")
|
|
throw("mem: infinite loop")
|
|
}
|
|
if uintptr(unsafe.Pointer(p)) > uintptr(unsafe.Pointer(p.next)) {
|
|
print("runtime: ", unsafe.Pointer(p), " > ", unsafe.Pointer(p.next), "\n")
|
|
throw("mem: unordered list")
|
|
}
|
|
if uintptr(unsafe.Pointer(p))+p.size > uintptr(unsafe.Pointer(p.next)) {
|
|
print("runtime: ", unsafe.Pointer(p), "+", p.size, " > ", unsafe.Pointer(p.next), "\n")
|
|
throw("mem: overlapping blocks")
|
|
}
|
|
for b := add(unsafe.Pointer(p), unsafe.Sizeof(memHdr{})); uintptr(b) < uintptr(unsafe.Pointer(p))+p.size; b = add(b, 1) {
|
|
if *(*byte)(b) != 0 {
|
|
print("runtime: value at addr ", b, " with offset ", uintptr(b)-uintptr(unsafe.Pointer(p)), " in block ", p, " of size ", p.size, " is not zero\n")
|
|
throw("mem: uninitialised memory")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func memRound(p uintptr) uintptr {
|
|
return (p + _PAGESIZE - 1) &^ (_PAGESIZE - 1)
|
|
}
|
|
|
|
func initBloc() {
|
|
bloc = memRound(firstmoduledata.end)
|
|
}
|
|
|
|
func sbrk(n uintptr) unsafe.Pointer {
|
|
// Plan 9 sbrk from /sys/src/libc/9sys/sbrk.c
|
|
bl := bloc
|
|
n = memRound(n)
|
|
if brk_(unsafe.Pointer(bl+n)) < 0 {
|
|
return nil
|
|
}
|
|
bloc += n
|
|
return unsafe.Pointer(bl)
|
|
}
|
|
|
|
func sysAlloc(n uintptr, sysStat *uint64) unsafe.Pointer {
|
|
lock(&memlock)
|
|
p := memAlloc(n)
|
|
memCheck()
|
|
unlock(&memlock)
|
|
if p != nil {
|
|
mSysStatInc(sysStat, n)
|
|
}
|
|
return p
|
|
}
|
|
|
|
func sysFree(v unsafe.Pointer, n uintptr, sysStat *uint64) {
|
|
mSysStatDec(sysStat, n)
|
|
lock(&memlock)
|
|
memFree(v, n)
|
|
memCheck()
|
|
unlock(&memlock)
|
|
}
|
|
|
|
func sysUnused(v unsafe.Pointer, n uintptr) {
|
|
}
|
|
|
|
func sysUsed(v unsafe.Pointer, n uintptr) {
|
|
}
|
|
|
|
func sysMap(v unsafe.Pointer, n uintptr, reserved bool, sysStat *uint64) {
|
|
// sysReserve has already allocated all heap memory,
|
|
// but has not adjusted stats.
|
|
mSysStatInc(sysStat, n)
|
|
}
|
|
|
|
func sysFault(v unsafe.Pointer, n uintptr) {
|
|
}
|
|
|
|
func sysReserve(v unsafe.Pointer, n uintptr, reserved *bool) unsafe.Pointer {
|
|
*reserved = true
|
|
lock(&memlock)
|
|
p := memAlloc(n)
|
|
memCheck()
|
|
unlock(&memlock)
|
|
return p
|
|
}
|