1760c2415Smrg /**
2760c2415Smrg  * Contains OS-level routines needed by the garbage collector.
3760c2415Smrg  *
4760c2415Smrg  * Copyright: Copyright Digital Mars 2005 - 2013.
5760c2415Smrg  * License:   $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
6760c2415Smrg  * Authors:   Walter Bright, David Friedman, Sean Kelly, Leandro Lucarella
7760c2415Smrg  */
8760c2415Smrg 
9760c2415Smrg /*          Copyright Digital Mars 2005 - 2013.
10760c2415Smrg  * Distributed under the Boost Software License, Version 1.0.
11760c2415Smrg  *    (See accompanying file LICENSE or copy at
12760c2415Smrg  *          http://www.boost.org/LICENSE_1_0.txt)
13760c2415Smrg  */
14760c2415Smrg module gc.os;
15760c2415Smrg 
16760c2415Smrg 
version(Windows)17760c2415Smrg version (Windows)
18760c2415Smrg {
19760c2415Smrg     import core.sys.windows.winbase : GetCurrentThreadId, VirtualAlloc, VirtualFree;
20760c2415Smrg     import core.sys.windows.winnt : MEM_COMMIT, MEM_RELEASE, MEM_RESERVE, PAGE_READWRITE;
21760c2415Smrg 
22760c2415Smrg     alias int pthread_t;
23760c2415Smrg 
24760c2415Smrg     pthread_t pthread_self() nothrow
25760c2415Smrg     {
26760c2415Smrg         return cast(pthread_t) GetCurrentThreadId();
27760c2415Smrg     }
28760c2415Smrg 
29760c2415Smrg     //version = GC_Use_Alloc_Win32;
30760c2415Smrg }
version(Posix)31760c2415Smrg else version (Posix)
32760c2415Smrg {
33760c2415Smrg     version (OSX)
34760c2415Smrg         version = Darwin;
35760c2415Smrg     else version (iOS)
36760c2415Smrg         version = Darwin;
37760c2415Smrg     else version (TVOS)
38760c2415Smrg         version = Darwin;
39760c2415Smrg     else version (WatchOS)
40760c2415Smrg         version = Darwin;
41760c2415Smrg 
42760c2415Smrg     import core.sys.posix.sys.mman;
43760c2415Smrg     version (FreeBSD) import core.sys.freebsd.sys.mman : MAP_ANON;
44760c2415Smrg     version (DragonFlyBSD) import core.sys.dragonflybsd.sys.mman : MAP_ANON;
45760c2415Smrg     version (NetBSD) import core.sys.netbsd.sys.mman : MAP_ANON;
46*0bfacb9bSmrg     version (OpenBSD) import core.sys.openbsd.sys.mman : MAP_ANON;
47760c2415Smrg     version (CRuntime_Glibc) import core.sys.linux.sys.mman : MAP_ANON;
48760c2415Smrg     version (Darwin) import core.sys.darwin.sys.mman : MAP_ANON;
49760c2415Smrg     version (CRuntime_UClibc) import core.sys.linux.sys.mman : MAP_ANON;
50760c2415Smrg     import core.stdc.stdlib;
51760c2415Smrg 
52760c2415Smrg     //version = GC_Use_Alloc_MMap;
53760c2415Smrg }
54760c2415Smrg else
55760c2415Smrg {
56760c2415Smrg     import core.stdc.stdlib;
57760c2415Smrg 
58760c2415Smrg     //version = GC_Use_Alloc_Malloc;
59760c2415Smrg }
60760c2415Smrg 
61760c2415Smrg /+
62760c2415Smrg static if (is(typeof(VirtualAlloc)))
63760c2415Smrg     version = GC_Use_Alloc_Win32;
64760c2415Smrg else static if (is(typeof(mmap)))
65760c2415Smrg     version = GC_Use_Alloc_MMap;
66760c2415Smrg else static if (is(typeof(valloc)))
67760c2415Smrg     version = GC_Use_Alloc_Valloc;
68760c2415Smrg else static if (is(typeof(malloc)))
69760c2415Smrg     version = GC_Use_Alloc_Malloc;
70760c2415Smrg else static assert(false, "No supported allocation methods available.");
71760c2415Smrg +/
72760c2415Smrg 
73760c2415Smrg static if (is(typeof(VirtualAlloc))) // version (GC_Use_Alloc_Win32)
74760c2415Smrg {
75760c2415Smrg     /**
76760c2415Smrg      * Map memory.
77760c2415Smrg      */
os_mem_map(size_t nbytes)78760c2415Smrg     void *os_mem_map(size_t nbytes) nothrow
79760c2415Smrg     {
80760c2415Smrg         return VirtualAlloc(null, nbytes, MEM_RESERVE | MEM_COMMIT,
81760c2415Smrg                 PAGE_READWRITE);
82760c2415Smrg     }
83760c2415Smrg 
84760c2415Smrg 
85760c2415Smrg     /**
86760c2415Smrg      * Unmap memory allocated with os_mem_map().
87760c2415Smrg      * Returns:
88760c2415Smrg      *      0       success
89760c2415Smrg      *      !=0     failure
90760c2415Smrg      */
os_mem_unmap(void * base,size_t nbytes)91760c2415Smrg     int os_mem_unmap(void *base, size_t nbytes) nothrow
92760c2415Smrg     {
93760c2415Smrg         return cast(int)(VirtualFree(base, 0, MEM_RELEASE) == 0);
94760c2415Smrg     }
95760c2415Smrg }
96760c2415Smrg else static if (is(typeof(mmap)))  // else version (GC_Use_Alloc_MMap)
97760c2415Smrg {
os_mem_map(size_t nbytes)98760c2415Smrg     void *os_mem_map(size_t nbytes) nothrow
99760c2415Smrg     {   void *p;
100760c2415Smrg 
101760c2415Smrg         p = mmap(null, nbytes, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
102760c2415Smrg         return (p == MAP_FAILED) ? null : p;
103760c2415Smrg     }
104760c2415Smrg 
105760c2415Smrg 
os_mem_unmap(void * base,size_t nbytes)106760c2415Smrg     int os_mem_unmap(void *base, size_t nbytes) nothrow
107760c2415Smrg     {
108760c2415Smrg         return munmap(base, nbytes);
109760c2415Smrg     }
110760c2415Smrg }
111760c2415Smrg else static if (is(typeof(valloc))) // else version (GC_Use_Alloc_Valloc)
112760c2415Smrg {
os_mem_map(size_t nbytes)113760c2415Smrg     void *os_mem_map(size_t nbytes) nothrow
114760c2415Smrg     {
115760c2415Smrg         return valloc(nbytes);
116760c2415Smrg     }
117760c2415Smrg 
118760c2415Smrg 
os_mem_unmap(void * base,size_t nbytes)119760c2415Smrg     int os_mem_unmap(void *base, size_t nbytes) nothrow
120760c2415Smrg     {
121760c2415Smrg         free(base);
122760c2415Smrg         return 0;
123760c2415Smrg     }
124760c2415Smrg }
125760c2415Smrg else static if (is(typeof(malloc))) // else version (GC_Use_Alloc_Malloc)
126760c2415Smrg {
127760c2415Smrg     // NOTE: This assumes malloc granularity is at least (void*).sizeof.  If
128760c2415Smrg     //       (req_size + PAGESIZE) is allocated, and the pointer is rounded up
129760c2415Smrg     //       to PAGESIZE alignment, there will be space for a void* at the end
130760c2415Smrg     //       after PAGESIZE bytes used by the GC.
131760c2415Smrg 
132760c2415Smrg 
133760c2415Smrg     import gc.gc;
134760c2415Smrg 
135760c2415Smrg 
136760c2415Smrg     const size_t PAGE_MASK = PAGESIZE - 1;
137760c2415Smrg 
138760c2415Smrg 
os_mem_map(size_t nbytes)139760c2415Smrg     void *os_mem_map(size_t nbytes) nothrow
140760c2415Smrg     {   byte *p, q;
141760c2415Smrg         p = cast(byte *) malloc(nbytes + PAGESIZE);
142760c2415Smrg         q = p + ((PAGESIZE - ((cast(size_t) p & PAGE_MASK))) & PAGE_MASK);
143760c2415Smrg         * cast(void**)(q + nbytes) = p;
144760c2415Smrg         return q;
145760c2415Smrg     }
146760c2415Smrg 
147760c2415Smrg 
os_mem_unmap(void * base,size_t nbytes)148760c2415Smrg     int os_mem_unmap(void *base, size_t nbytes) nothrow
149760c2415Smrg     {
150760c2415Smrg         free( *cast(void**)( cast(byte*) base + nbytes ) );
151760c2415Smrg         return 0;
152760c2415Smrg     }
153760c2415Smrg }
154760c2415Smrg else
155760c2415Smrg {
156760c2415Smrg     static assert(false, "No supported allocation methods available.");
157760c2415Smrg }
158760c2415Smrg 
159760c2415Smrg /**
160760c2415Smrg    Check for any kind of memory pressure.
161760c2415Smrg 
162760c2415Smrg    Params:
163760c2415Smrg       mapped = the amount of memory mapped by the GC in bytes
164760c2415Smrg    Returns:
165760c2415Smrg        true if memory is scarce
166760c2415Smrg */
167760c2415Smrg // TOOD: get virtual mem sizes and current usage from OS
168760c2415Smrg // TODO: compare current RSS and avail. physical memory
version(Windows)169760c2415Smrg version (Windows)
170760c2415Smrg {
171760c2415Smrg     bool isLowOnMem(size_t mapped) nothrow @nogc
172760c2415Smrg     {
173760c2415Smrg         version (D_LP64)
174760c2415Smrg             return false;
175760c2415Smrg         else
176760c2415Smrg         {
177760c2415Smrg             import core.sys.windows.winbase : GlobalMemoryStatus, MEMORYSTATUS;
178760c2415Smrg             MEMORYSTATUS stat;
179760c2415Smrg             GlobalMemoryStatus(&stat);
180760c2415Smrg             // Less than 5 % of virtual address space available
181760c2415Smrg             return stat.dwAvailVirtual < stat.dwTotalVirtual / 20;
182760c2415Smrg         }
183760c2415Smrg     }
184760c2415Smrg }
version(Darwin)185760c2415Smrg else version (Darwin)
186760c2415Smrg {
187760c2415Smrg     bool isLowOnMem(size_t mapped) nothrow @nogc
188760c2415Smrg     {
189760c2415Smrg         enum GB = 2 ^^ 30;
190760c2415Smrg         version (D_LP64)
191760c2415Smrg             return false;
192760c2415Smrg         else
193760c2415Smrg         {
194760c2415Smrg             // 80 % of available 4GB is used for GC (excluding malloc and mmap)
195760c2415Smrg             enum size_t limit = 4UL * GB * 8 / 10;
196760c2415Smrg             return mapped > limit;
197760c2415Smrg         }
198760c2415Smrg     }
199760c2415Smrg }
200760c2415Smrg else
201760c2415Smrg {
isLowOnMem(size_t mapped)202760c2415Smrg     bool isLowOnMem(size_t mapped) nothrow @nogc
203760c2415Smrg     {
204760c2415Smrg         enum GB = 2 ^^ 30;
205760c2415Smrg         version (D_LP64)
206760c2415Smrg             return false;
207760c2415Smrg         else
208760c2415Smrg         {
209760c2415Smrg             // be conservative and assume 3GB
210760c2415Smrg             enum size_t limit = 3UL * GB * 8 / 10;
211760c2415Smrg             return mapped > limit;
212760c2415Smrg         }
213760c2415Smrg     }
214760c2415Smrg }
215