]> git.ipfire.org Git - thirdparty/gcc.git/blob - libphobos/libdruntime/core/internal/gc/os.d
ipa-param-manip: Be careful about a reallocating hash_map
[thirdparty/gcc.git] / libphobos / libdruntime / core / internal / gc / os.d
1 /**
2 * Contains OS-level routines needed by the garbage collector.
3 *
4 * Copyright: D Language Foundation 2005 - 2021.
5 * License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
6 * Authors: Walter Bright, David Friedman, Sean Kelly, Leandro Lucarella
7 */
8 module core.internal.gc.os;
9
10
11 version (Windows)
12 {
13 import core.sys.windows.winbase : GetCurrentThreadId, VirtualAlloc, VirtualFree;
14 import core.sys.windows.winnt : MEM_COMMIT, MEM_RELEASE, MEM_RESERVE, PAGE_READWRITE;
15
16 alias int pthread_t;
17
18 pthread_t pthread_self() nothrow
19 {
20 return cast(pthread_t) GetCurrentThreadId();
21 }
22
23 //version = GC_Use_Alloc_Win32;
24 }
25 else version (Posix)
26 {
27 version (OSX)
28 version = Darwin;
29 else version (iOS)
30 version = Darwin;
31 else version (TVOS)
32 version = Darwin;
33 else version (WatchOS)
34 version = Darwin;
35
36 import core.sys.posix.sys.mman;
37 import core.stdc.stdlib;
38
39
40 /// Possible results for the wait_pid() function.
41 enum ChildStatus
42 {
43 done, /// The process has finished successfully
44 running, /// The process is still running
45 error /// There was an error waiting for the process
46 }
47
48 /**
49 * Wait for a process with PID pid to finish.
50 *
51 * If block is false, this function will not block, and return ChildStatus.running if
52 * the process is still running. Otherwise it will return always ChildStatus.done
53 * (unless there is an error, in which case ChildStatus.error is returned).
54 */
55 ChildStatus wait_pid(pid_t pid, bool block = true) nothrow @nogc
56 {
57 import core.exception : onForkError;
58
59 int status = void;
60 pid_t waited_pid = void;
61 // In the case where we are blocking, we need to consider signals
62 // arriving while we wait, and resume the waiting if EINTR is returned
63 do {
64 errno = 0;
65 waited_pid = waitpid(pid, &status, block ? 0 : WNOHANG);
66 }
67 while (waited_pid == -1 && errno == EINTR);
68 if (waited_pid == 0)
69 return ChildStatus.running;
70 else if (errno == ECHILD)
71 return ChildStatus.done; // someone called posix.syswait
72 else if (waited_pid != pid || status != 0)
73 {
74 onForkError();
75 return ChildStatus.error;
76 }
77 return ChildStatus.done;
78 }
79
80 public import core.sys.posix.unistd: pid_t, fork;
81 import core.sys.posix.sys.wait: waitpid, WNOHANG;
82 import core.stdc.errno: errno, EINTR, ECHILD;
83
84 //version = GC_Use_Alloc_MMap;
85 }
86 else
87 {
88 import core.stdc.stdlib;
89
90 //version = GC_Use_Alloc_Malloc;
91 }
92
93 /+
94 static if (is(typeof(VirtualAlloc)))
95 version = GC_Use_Alloc_Win32;
96 else static if (is(typeof(mmap)))
97 version = GC_Use_Alloc_MMap;
98 else static if (is(typeof(valloc)))
99 version = GC_Use_Alloc_Valloc;
100 else static if (is(typeof(malloc)))
101 version = GC_Use_Alloc_Malloc;
102 else static assert(false, "No supported allocation methods available.");
103 +/
104
105 static if (is(typeof(VirtualAlloc))) // version (GC_Use_Alloc_Win32)
106 {
107 /**
108 * Indicates if an implementation supports fork().
109 *
110 * The value shown here is just demostrative, the real value is defined based
111 * on the OS it's being compiled in.
112 * enum HaveFork = true;
113 */
114 enum HaveFork = false;
115
116 /**
117 * Map memory.
118 */
119 void *os_mem_map(size_t nbytes) nothrow @nogc
120 {
121 return VirtualAlloc(null, nbytes, MEM_RESERVE | MEM_COMMIT,
122 PAGE_READWRITE);
123 }
124
125
126 /**
127 * Unmap memory allocated with os_mem_map().
128 * Returns:
129 * 0 success
130 * !=0 failure
131 */
132 int os_mem_unmap(void *base, size_t nbytes) nothrow @nogc
133 {
134 return cast(int)(VirtualFree(base, 0, MEM_RELEASE) == 0);
135 }
136 }
137 else static if (is(typeof(mmap))) // else version (GC_Use_Alloc_MMap)
138 {
139 enum HaveFork = true;
140
141 void *os_mem_map(size_t nbytes, bool share = false) nothrow @nogc
142 { void *p;
143
144 auto map_f = share ? MAP_SHARED : MAP_PRIVATE;
145 p = mmap(null, nbytes, PROT_READ | PROT_WRITE, map_f | MAP_ANON, -1, 0);
146 return (p == MAP_FAILED) ? null : p;
147 }
148
149
150 int os_mem_unmap(void *base, size_t nbytes) nothrow @nogc
151 {
152 return munmap(base, nbytes);
153 }
154 }
155 else static if (is(typeof(valloc))) // else version (GC_Use_Alloc_Valloc)
156 {
157 enum HaveFork = false;
158
159 void *os_mem_map(size_t nbytes) nothrow @nogc
160 {
161 return valloc(nbytes);
162 }
163
164
165 int os_mem_unmap(void *base, size_t nbytes) nothrow @nogc
166 {
167 free(base);
168 return 0;
169 }
170 }
171 else static if (is(typeof(malloc))) // else version (GC_Use_Alloc_Malloc)
172 {
173 // NOTE: This assumes malloc granularity is at least (void*).sizeof. If
174 // (req_size + PAGESIZE) is allocated, and the pointer is rounded up
175 // to PAGESIZE alignment, there will be space for a void* at the end
176 // after PAGESIZE bytes used by the GC.
177
178 enum HaveFork = false;
179
180 import core.internal.gc.impl.conservative.gc;
181
182
183 const size_t PAGE_MASK = PAGESIZE - 1;
184
185
186 void *os_mem_map(size_t nbytes) nothrow @nogc
187 { byte *p, q;
188 p = cast(byte *) malloc(nbytes + PAGESIZE);
189 if (!p)
190 return null;
191 q = p + ((PAGESIZE - ((cast(size_t) p & PAGE_MASK))) & PAGE_MASK);
192 * cast(void**)(q + nbytes) = p;
193 return q;
194 }
195
196
197 int os_mem_unmap(void *base, size_t nbytes) nothrow @nogc
198 {
199 free( *cast(void**)( cast(byte*) base + nbytes ) );
200 return 0;
201 }
202 }
203 else
204 {
205 static assert(false, "No supported allocation methods available.");
206 }
207
208 /**
209 Check for any kind of memory pressure.
210
211 Params:
212 mapped = the amount of memory mapped by the GC in bytes
213 Returns:
214 true if memory is scarce
215 */
216 // TOOD: get virtual mem sizes and current usage from OS
217 // TODO: compare current RSS and avail. physical memory
218 version (Windows)
219 {
220 bool isLowOnMem(size_t mapped) nothrow @nogc
221 {
222 version (D_LP64)
223 return false;
224 else
225 {
226 import core.sys.windows.winbase : GlobalMemoryStatus, MEMORYSTATUS;
227 MEMORYSTATUS stat;
228 GlobalMemoryStatus(&stat);
229 // Less than 5 % of virtual address space available
230 return stat.dwAvailVirtual < stat.dwTotalVirtual / 20;
231 }
232 }
233 }
234 else version (Darwin)
235 {
236 bool isLowOnMem(size_t mapped) nothrow @nogc
237 {
238 enum GB = 2 ^^ 30;
239 version (D_LP64)
240 return false;
241 else
242 {
243 // 80 % of available 4GB is used for GC (excluding malloc and mmap)
244 enum size_t limit = 4UL * GB * 8 / 10;
245 return mapped > limit;
246 }
247 }
248 }
249 else
250 {
251 bool isLowOnMem(size_t mapped) nothrow @nogc
252 {
253 enum GB = 2 ^^ 30;
254 version (D_LP64)
255 return false;
256 else
257 {
258 // be conservative and assume 3GB
259 enum size_t limit = 3UL * GB * 8 / 10;
260 return mapped > limit;
261 }
262 }
263 }
264
265 /**
266 Get the size of available physical memory
267
268 Returns:
269 size of installed physical RAM
270 */
271 version (Windows)
272 {
273 ulong os_physical_mem() nothrow @nogc
274 {
275 import core.sys.windows.winbase : GlobalMemoryStatus, MEMORYSTATUS;
276 MEMORYSTATUS stat;
277 GlobalMemoryStatus(&stat);
278 return stat.dwTotalPhys; // limited to 4GB for Win32
279 }
280 }
281 else version (Darwin)
282 {
283 extern (C) int sysctl(const int* name, uint namelen, void* oldp, size_t* oldlenp, const void* newp, size_t newlen) @nogc nothrow;
284 ulong os_physical_mem() nothrow @nogc
285 {
286 enum
287 {
288 CTL_HW = 6,
289 HW_MEMSIZE = 24,
290 }
291 int[2] mib = [ CTL_HW, HW_MEMSIZE ];
292 ulong system_memory_bytes;
293 size_t len = system_memory_bytes.sizeof;
294 if (sysctl(mib.ptr, 2, &system_memory_bytes, &len, null, 0) != 0)
295 return 0;
296 return system_memory_bytes;
297 }
298 }
299 else version (Posix)
300 {
301 ulong os_physical_mem() nothrow @nogc
302 {
303 import core.sys.posix.unistd : sysconf, _SC_PAGESIZE, _SC_PHYS_PAGES;
304 const pageSize = sysconf(_SC_PAGESIZE);
305 const pages = sysconf(_SC_PHYS_PAGES);
306 return pageSize * pages;
307 }
308 }