Fix r180999.
[gcc.git] / libgo / runtime / mem.c
1 #include <errno.h>
2 #include <unistd.h>
3
4 #include "runtime.h"
5 #include "arch.h"
6 #include "malloc.h"
7
8 #ifndef MAP_ANON
9 #ifdef MAP_ANONYMOUS
10 #define MAP_ANON MAP_ANONYMOUS
11 #else
12 #define USE_DEV_ZERO
13 #define MAP_ANON 0
14 #endif
15 #endif
16
17 #ifdef USE_DEV_ZERO
18 static int dev_zero = -1;
19 #endif
20
21 static _Bool
22 addrspace_free(void *v __attribute__ ((unused)), uintptr n __attribute__ ((unused)))
23 {
24 #ifdef HAVE_MINCORE
25 size_t page_size = getpagesize();
26 size_t off;
27 char one_byte;
28
29 errno = 0;
30 for(off = 0; off < n; off += page_size)
31 if(mincore((char *)v + off, page_size, (void *)&one_byte) != -1
32 || errno != ENOMEM)
33 return 0;
34 #endif
35 return 1;
36 }
37
38 void*
39 runtime_SysAlloc(uintptr n)
40 {
41 void *p;
42 int fd = -1;
43
44 mstats.sys += n;
45
46 #ifdef USE_DEV_ZERO
47 if (dev_zero == -1) {
48 dev_zero = open("/dev/zero", O_RDONLY);
49 if (dev_zero < 0) {
50 printf("open /dev/zero: errno=%d\n", errno);
51 exit(2);
52 }
53 }
54 fd = dev_zero;
55 #endif
56
57 p = runtime_mmap(nil, n, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_PRIVATE, fd, 0);
58 if (p == MAP_FAILED) {
59 if(errno == EACCES) {
60 printf("runtime: mmap: access denied\n");
61 printf("if you're running SELinux, enable execmem for this process.\n");
62 exit(2);
63 }
64 return nil;
65 }
66 return p;
67 }
68
69 void
70 runtime_SysUnused(void *v, uintptr n)
71 {
72 USED(v);
73 USED(n);
74 // TODO(rsc): call madvise MADV_DONTNEED
75 }
76
77 void
78 runtime_SysFree(void *v, uintptr n)
79 {
80 mstats.sys -= n;
81 runtime_munmap(v, n);
82 }
83
84 void*
85 runtime_SysReserve(void *v, uintptr n)
86 {
87 int fd = -1;
88 void *p;
89
90 // On 64-bit, people with ulimit -v set complain if we reserve too
91 // much address space. Instead, assume that the reservation is okay
92 // and check the assumption in SysMap.
93 if(sizeof(void*) == 8)
94 return v;
95
96 #ifdef USE_DEV_ZERO
97 if (dev_zero == -1) {
98 dev_zero = open("/dev/zero", O_RDONLY);
99 if (dev_zero < 0) {
100 printf("open /dev/zero: errno=%d\n", errno);
101 exit(2);
102 }
103 }
104 fd = dev_zero;
105 #endif
106
107 p = runtime_mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE, fd, 0);
108 if((uintptr)p < 4096 || -(uintptr)p < 4096) {
109 return nil;
110 }
111 return p;
112 }
113
114 void
115 runtime_SysMap(void *v, uintptr n)
116 {
117 void *p;
118 int fd = -1;
119
120 mstats.sys += n;
121
122 #ifdef USE_DEV_ZERO
123 if (dev_zero == -1) {
124 dev_zero = open("/dev/zero", O_RDONLY);
125 if (dev_zero < 0) {
126 printf("open /dev/zero: errno=%d\n", errno);
127 exit(2);
128 }
129 }
130 fd = dev_zero;
131 #endif
132
133 // On 64-bit, we don't actually have v reserved, so tread carefully.
134 if(sizeof(void*) == 8) {
135 p = runtime_mmap(v, n, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_PRIVATE, fd, 0);
136 if(p != v && addrspace_free(v, n)) {
137 // On some systems, mmap ignores v without
138 // MAP_FIXED, so retry if the address space is free.
139 p = runtime_mmap(v, n, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_FIXED|MAP_PRIVATE, fd, 0);
140 }
141 if(p != v) {
142 runtime_printf("runtime: address space conflict: map(%p) = %p\n", v, p);
143 runtime_throw("runtime: address space conflict");
144 }
145 return;
146 }
147
148 p = runtime_mmap(v, n, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_FIXED|MAP_PRIVATE, fd, 0);
149 if(p != v)
150 runtime_throw("runtime: cannot map pages in arena address space");
151 }