2 * Contains OS-level routines needed by the garbage collector.
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
8 module core.internal.gc.os;
13 import core.sys.windows.winbase : GetCurrentThreadId, VirtualAlloc, VirtualFree;
14 import core.sys.windows.winnt : MEM_COMMIT, MEM_RELEASE, MEM_RESERVE, PAGE_READWRITE;
18 pthread_t pthread_self() nothrow
20 return cast(pthread_t) GetCurrentThreadId();
23 //version = GC_Use_Alloc_Win32;
33 else version (WatchOS)
36 import core.sys.posix.sys.mman;
37 import core.stdc.stdlib;
40 /// Possible results for the wait_pid() function.
43 done, /// The process has finished successfully
44 running, /// The process is still running
45 error /// There was an error waiting for the process
49 * Wait for a process with PID pid to finish.
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).
55 ChildStatus wait_pid(pid_t pid, bool block = true) nothrow @nogc
57 import core.exception : onForkError;
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
65 waited_pid = waitpid(pid, &status, block ? 0 : WNOHANG);
67 while (waited_pid == -1 && errno == EINTR);
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)
75 return ChildStatus.error;
77 return ChildStatus.done;
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;
84 //version = GC_Use_Alloc_MMap;
88 import core.stdc.stdlib;
90 //version = GC_Use_Alloc_Malloc;
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.");
105 static if (is(typeof(VirtualAlloc))) // version (GC_Use_Alloc_Win32)
108 * Indicates if an implementation supports fork().
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;
114 enum HaveFork = false;
119 void *os_mem_map(size_t nbytes) nothrow @nogc
121 return VirtualAlloc(null, nbytes, MEM_RESERVE | MEM_COMMIT,
127 * Unmap memory allocated with os_mem_map().
132 int os_mem_unmap(void *base, size_t nbytes) nothrow @nogc
134 return cast(int)(VirtualFree(base, 0, MEM_RELEASE) == 0);
137 else static if (is(typeof(mmap))) // else version (GC_Use_Alloc_MMap)
139 enum HaveFork = true;
141 void *os_mem_map(size_t nbytes, bool share = false) nothrow @nogc
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;
150 int os_mem_unmap(void *base, size_t nbytes) nothrow @nogc
152 return munmap(base, nbytes);
155 else static if (is(typeof(valloc))) // else version (GC_Use_Alloc_Valloc)
157 enum HaveFork = false;
159 void *os_mem_map(size_t nbytes) nothrow @nogc
161 return valloc(nbytes);
165 int os_mem_unmap(void *base, size_t nbytes) nothrow @nogc
171 else static if (is(typeof(malloc))) // else version (GC_Use_Alloc_Malloc)
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.
178 enum HaveFork = false;
180 import core.internal.gc.impl.conservative.gc;
183 const size_t PAGE_MASK = PAGESIZE - 1;
186 void *os_mem_map(size_t nbytes) nothrow @nogc
188 p = cast(byte *) malloc(nbytes + PAGESIZE);
191 q = p + ((PAGESIZE - ((cast(size_t) p & PAGE_MASK))) & PAGE_MASK);
192 * cast(void**)(q + nbytes) = p;
197 int os_mem_unmap(void *base, size_t nbytes) nothrow @nogc
199 free( *cast(void**)( cast(byte*) base + nbytes ) );
205 static assert(false, "No supported allocation methods available.");
209 Check for any kind of memory pressure.
212 mapped = the amount of memory mapped by the GC in bytes
214 true if memory is scarce
216 // TOOD: get virtual mem sizes and current usage from OS
217 // TODO: compare current RSS and avail. physical memory
220 bool isLowOnMem(size_t mapped) nothrow @nogc
226 import core.sys.windows.winbase : GlobalMemoryStatus, MEMORYSTATUS;
228 GlobalMemoryStatus(&stat);
229 // Less than 5 % of virtual address space available
230 return stat.dwAvailVirtual < stat.dwTotalVirtual / 20;
234 else version (Darwin)
236 bool isLowOnMem(size_t mapped) nothrow @nogc
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;
251 bool isLowOnMem(size_t mapped) nothrow @nogc
258 // be conservative and assume 3GB
259 enum size_t limit = 3UL * GB * 8 / 10;
260 return mapped > limit;
266 Get the size of available physical memory
269 size of installed physical RAM
273 ulong os_physical_mem() nothrow @nogc
275 import core.sys.windows.winbase : GlobalMemoryStatus, MEMORYSTATUS;
277 GlobalMemoryStatus(&stat);
278 return stat.dwTotalPhys; // limited to 4GB for Win32
281 else version (Darwin)
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
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)
296 return system_memory_bytes;
301 ulong os_physical_mem() nothrow @nogc
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;