github.com/zach-klippenstein/go@v0.0.0-20150108044943-fcfbeb3adf58/src/runtime/mem_linux.go (about)

     1  // Copyright 2010 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  const (
    10  	_PAGE_SIZE = _PhysPageSize
    11  	_EACCES    = 13
    12  )
    13  
    14  // NOTE: vec must be just 1 byte long here.
    15  // Mincore returns ENOMEM if any of the pages are unmapped,
    16  // but we want to know that all of the pages are unmapped.
    17  // To make these the same, we can only ask about one page
    18  // at a time. See golang.org/issue/7476.
    19  var addrspace_vec [1]byte
    20  
    21  func addrspace_free(v unsafe.Pointer, n uintptr) bool {
    22  	var chunk uintptr
    23  	for off := uintptr(0); off < n; off += chunk {
    24  		chunk = _PAGE_SIZE * uintptr(len(addrspace_vec))
    25  		if chunk > (n - off) {
    26  			chunk = n - off
    27  		}
    28  		errval := mincore(unsafe.Pointer(uintptr(v)+off), chunk, &addrspace_vec[0])
    29  		// ENOMEM means unmapped, which is what we want.
    30  		// Anything else we assume means the pages are mapped.
    31  		if errval != -_ENOMEM {
    32  			return false
    33  		}
    34  	}
    35  	return true
    36  }
    37  
    38  func mmap_fixed(v unsafe.Pointer, n uintptr, prot, flags, fd int32, offset uint32) unsafe.Pointer {
    39  	p := mmap(v, n, prot, flags, fd, offset)
    40  	// On some systems, mmap ignores v without
    41  	// MAP_FIXED, so retry if the address space is free.
    42  	if p != v && addrspace_free(v, n) {
    43  		if uintptr(p) > 4096 {
    44  			munmap(p, n)
    45  		}
    46  		p = mmap(v, n, prot, flags|_MAP_FIXED, fd, offset)
    47  	}
    48  	return p
    49  }
    50  
    51  //go:nosplit
    52  func sysAlloc(n uintptr, stat *uint64) unsafe.Pointer {
    53  	p := mmap(nil, n, _PROT_READ|_PROT_WRITE, _MAP_ANON|_MAP_PRIVATE, -1, 0)
    54  	if uintptr(p) < 4096 {
    55  		if uintptr(p) == _EACCES {
    56  			print("runtime: mmap: access denied\n")
    57  			print("if you're running SELinux, enable execmem for this process.\n")
    58  			exit(2)
    59  		}
    60  		if uintptr(p) == _EAGAIN {
    61  			print("runtime: mmap: too much locked memory (check 'ulimit -l').\n")
    62  			exit(2)
    63  		}
    64  		return nil
    65  	}
    66  	xadd64(stat, int64(n))
    67  	return p
    68  }
    69  
    70  func sysUnused(v unsafe.Pointer, n uintptr) {
    71  	madvise(v, n, _MADV_DONTNEED)
    72  }
    73  
    74  func sysUsed(v unsafe.Pointer, n uintptr) {
    75  }
    76  
    77  func sysFree(v unsafe.Pointer, n uintptr, stat *uint64) {
    78  	xadd64(stat, -int64(n))
    79  	munmap(v, n)
    80  }
    81  
    82  func sysFault(v unsafe.Pointer, n uintptr) {
    83  	mmap(v, n, _PROT_NONE, _MAP_ANON|_MAP_PRIVATE|_MAP_FIXED, -1, 0)
    84  }
    85  
    86  func sysReserve(v unsafe.Pointer, n uintptr, reserved *bool) unsafe.Pointer {
    87  	// On 64-bit, people with ulimit -v set complain if we reserve too
    88  	// much address space.  Instead, assume that the reservation is okay
    89  	// if we can reserve at least 64K and check the assumption in SysMap.
    90  	// Only user-mode Linux (UML) rejects these requests.
    91  	if ptrSize == 8 && uint64(n) > 1<<32 {
    92  		p := mmap_fixed(v, 64<<10, _PROT_NONE, _MAP_ANON|_MAP_PRIVATE, -1, 0)
    93  		if p != v {
    94  			if uintptr(p) >= 4096 {
    95  				munmap(p, 64<<10)
    96  			}
    97  			return nil
    98  		}
    99  		munmap(p, 64<<10)
   100  		*reserved = false
   101  		return v
   102  	}
   103  
   104  	p := mmap(v, n, _PROT_NONE, _MAP_ANON|_MAP_PRIVATE, -1, 0)
   105  	if uintptr(p) < 4096 {
   106  		return nil
   107  	}
   108  	*reserved = true
   109  	return p
   110  }
   111  
   112  func sysMap(v unsafe.Pointer, n uintptr, reserved bool, stat *uint64) {
   113  	xadd64(stat, int64(n))
   114  
   115  	// On 64-bit, we don't actually have v reserved, so tread carefully.
   116  	if !reserved {
   117  		p := mmap_fixed(v, n, _PROT_READ|_PROT_WRITE, _MAP_ANON|_MAP_PRIVATE, -1, 0)
   118  		if uintptr(p) == _ENOMEM {
   119  			throw("runtime: out of memory")
   120  		}
   121  		if p != v {
   122  			print("runtime: address space conflict: map(", v, ") = ", p, "\n")
   123  			throw("runtime: address space conflict")
   124  		}
   125  		return
   126  	}
   127  
   128  	p := mmap(v, n, _PROT_READ|_PROT_WRITE, _MAP_ANON|_MAP_FIXED|_MAP_PRIVATE, -1, 0)
   129  	if uintptr(p) == _ENOMEM {
   130  		throw("runtime: out of memory")
   131  	}
   132  	if p != v {
   133  		throw("runtime: cannot map pages in arena address space")
   134  	}
   135  }