github.com/xushiwei/go@v0.0.0-20130601165731-2b9d83f45bc9/src/pkg/runtime/mem_linux.c (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  #include "runtime.h"
     6  #include "arch_GOARCH.h"
     7  #include "defs_GOOS_GOARCH.h"
     8  #include "os_GOOS.h"
     9  #include "malloc.h"
    10  
    11  enum
    12  {
    13  	_PAGE_SIZE = 4096,
    14  };
    15  
    16  static int32
    17  addrspace_free(void *v, uintptr n)
    18  {
    19  	int32 errval;
    20  	uintptr chunk;
    21  	uintptr off;
    22  	static byte vec[4096];
    23  
    24  	for(off = 0; off < n; off += chunk) {
    25  		chunk = _PAGE_SIZE * sizeof vec;
    26  		if(chunk > (n - off))
    27  			chunk = n - off;
    28  		errval = runtime·mincore((int8*)v + off, chunk, vec);
    29  		// errval is 0 if success, or -(error_code) if error.
    30  		if (errval == 0 || errval != -ENOMEM)
    31  			return 0;
    32  	}
    33  	return 1;
    34  }
    35  
    36  static void *
    37  mmap_fixed(byte *v, uintptr n, int32 prot, int32 flags, int32 fd, uint32 offset)
    38  {
    39  	void *p;
    40  
    41  	p = runtime·mmap(v, n, prot, flags, fd, offset);
    42  	if(p != v && addrspace_free(v, n)) {
    43  		// On some systems, mmap ignores v without
    44  		// MAP_FIXED, so retry if the address space is free.
    45  		if(p > (void*)4096)
    46  			runtime·munmap(p, n);
    47  		p = runtime·mmap(v, n, prot, flags|MAP_FIXED, fd, offset);
    48  	}
    49  	return p;
    50  }
    51  
    52  void*
    53  runtime·SysAlloc(uintptr n)
    54  {
    55  	void *p;
    56  
    57  	mstats.sys += n;
    58  	p = runtime·mmap(nil, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
    59  	if(p < (void*)4096) {
    60  		if(p == (void*)EACCES) {
    61  			runtime·printf("runtime: mmap: access denied\n");
    62  			runtime·printf("if you're running SELinux, enable execmem for this process.\n");
    63  			runtime·exit(2);
    64  		}
    65  		if(p == (void*)EAGAIN) {
    66  			runtime·printf("runtime: mmap: too much locked memory (check 'ulimit -l').\n");
    67  			runtime·exit(2);
    68  		}
    69  		return nil;
    70  	}
    71  	return p;
    72  }
    73  
    74  void
    75  runtime·SysUnused(void *v, uintptr n)
    76  {
    77  	runtime·madvise(v, n, MADV_DONTNEED);
    78  }
    79  
    80  void
    81  runtime·SysFree(void *v, uintptr n)
    82  {
    83  	mstats.sys -= n;
    84  	runtime·munmap(v, n);
    85  }
    86  
    87  void*
    88  runtime·SysReserve(void *v, uintptr n)
    89  {
    90  	void *p;
    91  
    92  	// On 64-bit, people with ulimit -v set complain if we reserve too
    93  	// much address space.  Instead, assume that the reservation is okay
    94  	// if we can reserve at least 64K and check the assumption in SysMap.
    95  	// Only user-mode Linux (UML) rejects these requests.
    96  	if(sizeof(void*) == 8 && (uintptr)v >= 0xffffffffU) {
    97  		p = mmap_fixed(v, 64<<10, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
    98  		if (p != v)
    99  			return nil;
   100  		runtime·munmap(p, 64<<10);
   101  		return v;
   102  	}
   103  	
   104  	p = runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
   105  	if((uintptr)p < 4096 || -(uintptr)p < 4096)
   106  		return nil;
   107  	return p;
   108  }
   109  
   110  void
   111  runtime·SysMap(void *v, uintptr n)
   112  {
   113  	void *p;
   114  	
   115  	mstats.sys += n;
   116  
   117  	// On 64-bit, we don't actually have v reserved, so tread carefully.
   118  	if(sizeof(void*) == 8 && (uintptr)v >= 0xffffffffU) {
   119  		p = mmap_fixed(v, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
   120  		if(p == (void*)ENOMEM)
   121  			runtime·throw("runtime: out of memory");
   122  		if(p != v) {
   123  			runtime·printf("runtime: address space conflict: map(%p) = %p\n", v, p);
   124  			runtime·throw("runtime: address space conflict");
   125  		}
   126  		return;
   127  	}
   128  
   129  	p = runtime·mmap(v, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_FIXED|MAP_PRIVATE, -1, 0);
   130  	if(p == (void*)ENOMEM)
   131  		runtime·throw("runtime: out of memory");
   132  	if(p != v)
   133  		runtime·throw("runtime: cannot map pages in arena address space");
   134  }