Source file src/runtime/mem_sbrk.go

     1  // Copyright 2023 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  //go:build plan9 || wasm
     6  
     7  package runtime
     8  
     9  import "unsafe"
    10  
    11  const memDebug = false
    12  
    13  var bloc uintptr
    14  var blocMax uintptr
    15  var memlock mutex
    16  
    17  type memHdr struct {
    18  	next memHdrPtr
    19  	size uintptr
    20  }
    21  
    22  var memFreelist memHdrPtr // sorted in ascending order
    23  
    24  type memHdrPtr uintptr
    25  
    26  func (p memHdrPtr) ptr() *memHdr   { return (*memHdr)(unsafe.Pointer(p)) }
    27  func (p *memHdrPtr) set(x *memHdr) { *p = memHdrPtr(unsafe.Pointer(x)) }
    28  
    29  func memAlloc(n uintptr) unsafe.Pointer {
    30  	n = memRound(n)
    31  	var prevp *memHdr
    32  	for p := memFreelist.ptr(); p != nil; p = p.next.ptr() {
    33  		if p.size >= n {
    34  			if p.size == n {
    35  				if prevp != nil {
    36  					prevp.next = p.next
    37  				} else {
    38  					memFreelist = p.next
    39  				}
    40  			} else {
    41  				p.size -= n
    42  				p = (*memHdr)(add(unsafe.Pointer(p), p.size))
    43  			}
    44  			*p = memHdr{}
    45  			return unsafe.Pointer(p)
    46  		}
    47  		prevp = p
    48  	}
    49  	return sbrk(n)
    50  }
    51  
    52  func memFree(ap unsafe.Pointer, n uintptr) {
    53  	n = memRound(n)
    54  	memclrNoHeapPointers(ap, n)
    55  	bp := (*memHdr)(ap)
    56  	bp.size = n
    57  	bpn := uintptr(ap)
    58  	if memFreelist == 0 {
    59  		bp.next = 0
    60  		memFreelist.set(bp)
    61  		return
    62  	}
    63  	p := memFreelist.ptr()
    64  	if bpn < uintptr(unsafe.Pointer(p)) {
    65  		memFreelist.set(bp)
    66  		if bpn+bp.size == uintptr(unsafe.Pointer(p)) {
    67  			bp.size += p.size
    68  			bp.next = p.next
    69  			*p = memHdr{}
    70  		} else {
    71  			bp.next.set(p)
    72  		}
    73  		return
    74  	}
    75  	for ; p.next != 0; p = p.next.ptr() {
    76  		if bpn > uintptr(unsafe.Pointer(p)) && bpn < uintptr(unsafe.Pointer(p.next)) {
    77  			break
    78  		}
    79  	}
    80  	if bpn+bp.size == uintptr(unsafe.Pointer(p.next)) {
    81  		bp.size += p.next.ptr().size
    82  		bp.next = p.next.ptr().next
    83  		*p.next.ptr() = memHdr{}
    84  	} else {
    85  		bp.next = p.next
    86  	}
    87  	if uintptr(unsafe.Pointer(p))+p.size == bpn {
    88  		p.size += bp.size
    89  		p.next = bp.next
    90  		*bp = memHdr{}
    91  	} else {
    92  		p.next.set(bp)
    93  	}
    94  }
    95  
    96  func memCheck() {
    97  	if !memDebug {
    98  		return
    99  	}
   100  	for p := memFreelist.ptr(); p != nil && p.next != 0; p = p.next.ptr() {
   101  		if uintptr(unsafe.Pointer(p)) == uintptr(unsafe.Pointer(p.next)) {
   102  			print("runtime: ", unsafe.Pointer(p), " == ", unsafe.Pointer(p.next), "\n")
   103  			throw("mem: infinite loop")
   104  		}
   105  		if uintptr(unsafe.Pointer(p)) > uintptr(unsafe.Pointer(p.next)) {
   106  			print("runtime: ", unsafe.Pointer(p), " > ", unsafe.Pointer(p.next), "\n")
   107  			throw("mem: unordered list")
   108  		}
   109  		if uintptr(unsafe.Pointer(p))+p.size > uintptr(unsafe.Pointer(p.next)) {
   110  			print("runtime: ", unsafe.Pointer(p), "+", p.size, " > ", unsafe.Pointer(p.next), "\n")
   111  			throw("mem: overlapping blocks")
   112  		}
   113  		for b := add(unsafe.Pointer(p), unsafe.Sizeof(memHdr{})); uintptr(b) < uintptr(unsafe.Pointer(p))+p.size; b = add(b, 1) {
   114  			if *(*byte)(b) != 0 {
   115  				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")
   116  				throw("mem: uninitialised memory")
   117  			}
   118  		}
   119  	}
   120  }
   121  
   122  func memRound(p uintptr) uintptr {
   123  	return alignUp(p, physPageSize)
   124  }
   125  
   126  func initBloc() {
   127  	bloc = memRound(firstmoduledata.end)
   128  	blocMax = bloc
   129  }
   130  
   131  func sysAllocOS(n uintptr) unsafe.Pointer {
   132  	lock(&memlock)
   133  	p := memAlloc(n)
   134  	memCheck()
   135  	unlock(&memlock)
   136  	return p
   137  }
   138  
   139  func sysFreeOS(v unsafe.Pointer, n uintptr) {
   140  	lock(&memlock)
   141  	if uintptr(v)+n == bloc {
   142  		// Address range being freed is at the end of memory,
   143  		// so record a new lower value for end of memory.
   144  		// Can't actually shrink address space because segment is shared.
   145  		memclrNoHeapPointers(v, n)
   146  		bloc -= n
   147  	} else {
   148  		memFree(v, n)
   149  		memCheck()
   150  	}
   151  	unlock(&memlock)
   152  }
   153  
   154  func sysUnusedOS(v unsafe.Pointer, n uintptr) {
   155  }
   156  
   157  func sysUsedOS(v unsafe.Pointer, n uintptr) {
   158  }
   159  
   160  func sysHugePageOS(v unsafe.Pointer, n uintptr) {
   161  }
   162  
   163  func sysNoHugePageOS(v unsafe.Pointer, n uintptr) {
   164  }
   165  
   166  func sysHugePageCollapseOS(v unsafe.Pointer, n uintptr) {
   167  }
   168  
   169  func sysMapOS(v unsafe.Pointer, n uintptr) {
   170  }
   171  
   172  func sysFaultOS(v unsafe.Pointer, n uintptr) {
   173  }
   174  
   175  func sysReserveOS(v unsafe.Pointer, n uintptr) unsafe.Pointer {
   176  	lock(&memlock)
   177  	var p unsafe.Pointer
   178  	if uintptr(v) == bloc {
   179  		// Address hint is the current end of memory,
   180  		// so try to extend the address space.
   181  		p = sbrk(n)
   182  	}
   183  	if p == nil && v == nil {
   184  		p = memAlloc(n)
   185  		memCheck()
   186  	}
   187  	unlock(&memlock)
   188  	return p
   189  }
   190  

View as plain text