mirror of
https://github.com/golang/go
synced 2024-11-19 22:34:48 -07:00
519474451a
This is a subset of https://golang.org/cl/20022 with only the copyright header lines, so the next CL will be smaller and more reviewable. Go policy has been single space after periods in comments for some time. The copyright header template at: https://golang.org/doc/contribute.html#copyright also uses a single space. Make them all consistent. Change-Id: Icc26c6b8495c3820da6b171ca96a74701b4a01b0 Reviewed-on: https://go-review.googlesource.com/20111 Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org> Reviewed-by: Ian Lance Taylor <iant@golang.org> Reviewed-by: Matthew Dempsky <mdempsky@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org>
119 lines
3.7 KiB
Go
119 lines
3.7 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 (
|
|
_MEM_COMMIT = 0x1000
|
|
_MEM_RESERVE = 0x2000
|
|
_MEM_DECOMMIT = 0x4000
|
|
_MEM_RELEASE = 0x8000
|
|
|
|
_PAGE_READWRITE = 0x0004
|
|
_PAGE_NOACCESS = 0x0001
|
|
)
|
|
|
|
// Don't split the stack as this function may be invoked without a valid G,
|
|
// which prevents us from allocating more stack.
|
|
//go:nosplit
|
|
func sysAlloc(n uintptr, sysStat *uint64) unsafe.Pointer {
|
|
mSysStatInc(sysStat, n)
|
|
return unsafe.Pointer(stdcall4(_VirtualAlloc, 0, n, _MEM_COMMIT|_MEM_RESERVE, _PAGE_READWRITE))
|
|
}
|
|
|
|
func sysUnused(v unsafe.Pointer, n uintptr) {
|
|
r := stdcall3(_VirtualFree, uintptr(v), n, _MEM_DECOMMIT)
|
|
if r != 0 {
|
|
return
|
|
}
|
|
|
|
// Decommit failed. Usual reason is that we've merged memory from two different
|
|
// VirtualAlloc calls, and Windows will only let each VirtualFree handle pages from
|
|
// a single VirtualAlloc. It is okay to specify a subset of the pages from a single alloc,
|
|
// just not pages from multiple allocs. This is a rare case, arising only when we're
|
|
// trying to give memory back to the operating system, which happens on a time
|
|
// scale of minutes. It doesn't have to be terribly fast. Instead of extra bookkeeping
|
|
// on all our VirtualAlloc calls, try freeing successively smaller pieces until
|
|
// we manage to free something, and then repeat. This ends up being O(n log n)
|
|
// in the worst case, but that's fast enough.
|
|
for n > 0 {
|
|
small := n
|
|
for small >= 4096 && stdcall3(_VirtualFree, uintptr(v), small, _MEM_DECOMMIT) == 0 {
|
|
small /= 2
|
|
small &^= 4096 - 1
|
|
}
|
|
if small < 4096 {
|
|
print("runtime: VirtualFree of ", small, " bytes failed with errno=", getlasterror(), "\n")
|
|
throw("runtime: failed to decommit pages")
|
|
}
|
|
v = add(v, small)
|
|
n -= small
|
|
}
|
|
}
|
|
|
|
func sysUsed(v unsafe.Pointer, n uintptr) {
|
|
r := stdcall4(_VirtualAlloc, uintptr(v), n, _MEM_COMMIT, _PAGE_READWRITE)
|
|
if r == uintptr(v) {
|
|
return
|
|
}
|
|
|
|
// Commit failed. See SysUnused.
|
|
for n > 0 {
|
|
small := n
|
|
for small >= 4096 && stdcall4(_VirtualAlloc, uintptr(v), small, _MEM_COMMIT, _PAGE_READWRITE) == 0 {
|
|
small /= 2
|
|
small &^= 4096 - 1
|
|
}
|
|
if small < 4096 {
|
|
print("runtime: VirtualAlloc of ", small, " bytes failed with errno=", getlasterror(), "\n")
|
|
throw("runtime: failed to commit pages")
|
|
}
|
|
v = add(v, small)
|
|
n -= small
|
|
}
|
|
}
|
|
|
|
// Don't split the stack as this function may be invoked without a valid G,
|
|
// which prevents us from allocating more stack.
|
|
//go:nosplit
|
|
func sysFree(v unsafe.Pointer, n uintptr, sysStat *uint64) {
|
|
mSysStatDec(sysStat, n)
|
|
r := stdcall3(_VirtualFree, uintptr(v), 0, _MEM_RELEASE)
|
|
if r == 0 {
|
|
print("runtime: VirtualFree of ", n, " bytes failed with errno=", getlasterror(), "\n")
|
|
throw("runtime: failed to release pages")
|
|
}
|
|
}
|
|
|
|
func sysFault(v unsafe.Pointer, n uintptr) {
|
|
// SysUnused makes the memory inaccessible and prevents its reuse
|
|
sysUnused(v, n)
|
|
}
|
|
|
|
func sysReserve(v unsafe.Pointer, n uintptr, reserved *bool) unsafe.Pointer {
|
|
*reserved = true
|
|
// v is just a hint.
|
|
// First try at v.
|
|
v = unsafe.Pointer(stdcall4(_VirtualAlloc, uintptr(v), n, _MEM_RESERVE, _PAGE_READWRITE))
|
|
if v != nil {
|
|
return v
|
|
}
|
|
|
|
// Next let the kernel choose the address.
|
|
return unsafe.Pointer(stdcall4(_VirtualAlloc, 0, n, _MEM_RESERVE, _PAGE_READWRITE))
|
|
}
|
|
|
|
func sysMap(v unsafe.Pointer, n uintptr, reserved bool, sysStat *uint64) {
|
|
mSysStatInc(sysStat, n)
|
|
p := stdcall4(_VirtualAlloc, uintptr(v), n, _MEM_COMMIT, _PAGE_READWRITE)
|
|
if p != uintptr(v) {
|
|
print("runtime: VirtualAlloc of ", n, " bytes failed with errno=", getlasterror(), "\n")
|
|
throw("runtime: cannot map pages in arena address space")
|
|
}
|
|
}
|