mirror of
https://github.com/golang/go
synced 2024-10-01 22:18:32 -06:00
c2cdfbd1a7
Plan 9 won't let brk shrink the data segment if it's shared with other processes (which it is in the go runtime). So we keep track of the notional end of the segment as it moves up and down, and call brk only when it grows. Corrects CL 94776. Updates #23860. Fixes #24013. Change-Id: I754232decab81dfd71d690f77ee6097a17d9be11 Reviewed-on: https://go-review.googlesource.com/97595 Reviewed-by: David du Colombier <0intro@gmail.com> Reviewed-by: Austin Clements <austin@google.com> Run-TryBot: David du Colombier <0intro@gmail.com> TryBot-Result: Gobot Gobot <gobot@golang.org>
200 lines
4.5 KiB
Go
200 lines
4.5 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 blocMax uintptr
|
|
var memlock mutex
|
|
|
|
type memHdr struct {
|
|
next memHdrPtr
|
|
size uintptr
|
|
}
|
|
|
|
var memFreelist memHdrPtr // sorted in ascending order
|
|
|
|
type memHdrPtr uintptr
|
|
|
|
func (p memHdrPtr) ptr() *memHdr { return (*memHdr)(unsafe.Pointer(p)) }
|
|
func (p *memHdrPtr) set(x *memHdr) { *p = memHdrPtr(unsafe.Pointer(x)) }
|
|
|
|
func memAlloc(n uintptr) unsafe.Pointer {
|
|
n = memRound(n)
|
|
var prevp *memHdr
|
|
for p := memFreelist.ptr(); p != nil; p = p.next.ptr() {
|
|
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))
|
|
}
|
|
*p = memHdr{}
|
|
return unsafe.Pointer(p)
|
|
}
|
|
prevp = p
|
|
}
|
|
return sbrk(n)
|
|
}
|
|
|
|
func memFree(ap unsafe.Pointer, n uintptr) {
|
|
n = memRound(n)
|
|
memclrNoHeapPointers(ap, n)
|
|
bp := (*memHdr)(ap)
|
|
bp.size = n
|
|
bpn := uintptr(ap)
|
|
if memFreelist == 0 {
|
|
bp.next = 0
|
|
memFreelist.set(bp)
|
|
return
|
|
}
|
|
p := memFreelist.ptr()
|
|
if bpn < uintptr(unsafe.Pointer(p)) {
|
|
memFreelist.set(bp)
|
|
if bpn+bp.size == uintptr(unsafe.Pointer(p)) {
|
|
bp.size += p.size
|
|
bp.next = p.next
|
|
*p = memHdr{}
|
|
} else {
|
|
bp.next.set(p)
|
|
}
|
|
return
|
|
}
|
|
for ; p.next != 0; p = p.next.ptr() {
|
|
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.ptr().size
|
|
bp.next = p.next.ptr().next
|
|
*p.next.ptr() = memHdr{}
|
|
} else {
|
|
bp.next = p.next
|
|
}
|
|
if uintptr(unsafe.Pointer(p))+p.size == bpn {
|
|
p.size += bp.size
|
|
p.next = bp.next
|
|
*bp = memHdr{}
|
|
} else {
|
|
p.next.set(bp)
|
|
}
|
|
}
|
|
|
|
func memCheck() {
|
|
if memDebug == false {
|
|
return
|
|
}
|
|
for p := memFreelist.ptr(); p != nil && p.next != 0; p = p.next.ptr() {
|
|
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)
|
|
blocMax = bloc
|
|
}
|
|
|
|
func sbrk(n uintptr) unsafe.Pointer {
|
|
// Plan 9 sbrk from /sys/src/libc/9sys/sbrk.c
|
|
bl := bloc
|
|
n = memRound(n)
|
|
if bl+n > blocMax {
|
|
if brk_(unsafe.Pointer(bl+n)) < 0 {
|
|
return nil
|
|
}
|
|
blocMax = bl + n
|
|
}
|
|
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)
|
|
if uintptr(v)+n == bloc {
|
|
// Address range being freed is at the end of memory,
|
|
// so record a new lower value for end of memory.
|
|
// Can't actually shrink address space because segment is shared.
|
|
memclrNoHeapPointers(v, n)
|
|
bloc -= n
|
|
} else {
|
|
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, 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) unsafe.Pointer {
|
|
lock(&memlock)
|
|
var p unsafe.Pointer
|
|
if uintptr(v) == bloc {
|
|
// Address hint is the current end of memory,
|
|
// so try to extend the address space.
|
|
p = sbrk(n)
|
|
}
|
|
if p == nil {
|
|
p = memAlloc(n)
|
|
memCheck()
|
|
}
|
|
unlock(&memlock)
|
|
return p
|
|
}
|