1/** 2 * Contains OS-level routines needed by the garbage collector. 3 * 4 * Copyright: Copyright Digital Mars 2005 - 2013. 5 * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). 6 * Authors: Walter Bright, David Friedman, Sean Kelly, Leandro Lucarella 7 */ 8 9/* Copyright Digital Mars 2005 - 2013. 10 * Distributed under the Boost Software License, Version 1.0. 11 * (See accompanying file LICENSE or copy at 12 * http://www.boost.org/LICENSE_1_0.txt) 13 */ 14module gc.os; 15 16 17version (Windows) 18{ 19 import core.sys.windows.winbase : GetCurrentThreadId, VirtualAlloc, VirtualFree; 20 import core.sys.windows.winnt : MEM_COMMIT, MEM_RELEASE, MEM_RESERVE, PAGE_READWRITE; 21 22 alias int pthread_t; 23 24 pthread_t pthread_self() nothrow 25 { 26 return cast(pthread_t) GetCurrentThreadId(); 27 } 28 29 //version = GC_Use_Alloc_Win32; 30} 31else version (Posix) 32{ 33 version (OSX) 34 version = Darwin; 35 else version (iOS) 36 version = Darwin; 37 else version (TVOS) 38 version = Darwin; 39 else version (WatchOS) 40 version = Darwin; 41 42 import core.sys.posix.sys.mman; 43 version (FreeBSD) import core.sys.freebsd.sys.mman : MAP_ANON; 44 version (DragonFlyBSD) import core.sys.dragonflybsd.sys.mman : MAP_ANON; 45 version (NetBSD) import core.sys.netbsd.sys.mman : MAP_ANON; 46 version (OpenBSD) import core.sys.openbsd.sys.mman : MAP_ANON; 47 version (CRuntime_Glibc) import core.sys.linux.sys.mman : MAP_ANON; 48 version (Darwin) import core.sys.darwin.sys.mman : MAP_ANON; 49 version (CRuntime_UClibc) import core.sys.linux.sys.mman : MAP_ANON; 50 import core.stdc.stdlib; 51 52 //version = GC_Use_Alloc_MMap; 53} 54else 55{ 56 import core.stdc.stdlib; 57 58 //version = GC_Use_Alloc_Malloc; 59} 60 61/+ 62static if (is(typeof(VirtualAlloc))) 63 version = GC_Use_Alloc_Win32; 64else static if (is(typeof(mmap))) 65 version = GC_Use_Alloc_MMap; 66else static if (is(typeof(valloc))) 67 version = GC_Use_Alloc_Valloc; 68else static if (is(typeof(malloc))) 69 version = GC_Use_Alloc_Malloc; 70else static assert(false, "No supported allocation methods available."); 71+/ 72 73static if (is(typeof(VirtualAlloc))) // version (GC_Use_Alloc_Win32) 74{ 75 /** 76 * Map memory. 77 */ 78 void *os_mem_map(size_t nbytes) nothrow 79 { 80 return VirtualAlloc(null, nbytes, MEM_RESERVE | MEM_COMMIT, 81 PAGE_READWRITE); 82 } 83 84 85 /** 86 * Unmap memory allocated with os_mem_map(). 87 * Returns: 88 * 0 success 89 * !=0 failure 90 */ 91 int os_mem_unmap(void *base, size_t nbytes) nothrow 92 { 93 return cast(int)(VirtualFree(base, 0, MEM_RELEASE) == 0); 94 } 95} 96else static if (is(typeof(mmap))) // else version (GC_Use_Alloc_MMap) 97{ 98 void *os_mem_map(size_t nbytes) nothrow 99 { void *p; 100 101 p = mmap(null, nbytes, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); 102 return (p == MAP_FAILED) ? null : p; 103 } 104 105 106 int os_mem_unmap(void *base, size_t nbytes) nothrow 107 { 108 return munmap(base, nbytes); 109 } 110} 111else static if (is(typeof(valloc))) // else version (GC_Use_Alloc_Valloc) 112{ 113 void *os_mem_map(size_t nbytes) nothrow 114 { 115 return valloc(nbytes); 116 } 117 118 119 int os_mem_unmap(void *base, size_t nbytes) nothrow 120 { 121 free(base); 122 return 0; 123 } 124} 125else static if (is(typeof(malloc))) // else version (GC_Use_Alloc_Malloc) 126{ 127 // NOTE: This assumes malloc granularity is at least (void*).sizeof. If 128 // (req_size + PAGESIZE) is allocated, and the pointer is rounded up 129 // to PAGESIZE alignment, there will be space for a void* at the end 130 // after PAGESIZE bytes used by the GC. 131 132 133 import gc.gc; 134 135 136 const size_t PAGE_MASK = PAGESIZE - 1; 137 138 139 void *os_mem_map(size_t nbytes) nothrow 140 { byte *p, q; 141 p = cast(byte *) malloc(nbytes + PAGESIZE); 142 q = p + ((PAGESIZE - ((cast(size_t) p & PAGE_MASK))) & PAGE_MASK); 143 * cast(void**)(q + nbytes) = p; 144 return q; 145 } 146 147 148 int os_mem_unmap(void *base, size_t nbytes) nothrow 149 { 150 free( *cast(void**)( cast(byte*) base + nbytes ) ); 151 return 0; 152 } 153} 154else 155{ 156 static assert(false, "No supported allocation methods available."); 157} 158 159/** 160 Check for any kind of memory pressure. 161 162 Params: 163 mapped = the amount of memory mapped by the GC in bytes 164 Returns: 165 true if memory is scarce 166*/ 167// TOOD: get virtual mem sizes and current usage from OS 168// TODO: compare current RSS and avail. physical memory 169version (Windows) 170{ 171 bool isLowOnMem(size_t mapped) nothrow @nogc 172 { 173 version (D_LP64) 174 return false; 175 else 176 { 177 import core.sys.windows.winbase : GlobalMemoryStatus, MEMORYSTATUS; 178 MEMORYSTATUS stat; 179 GlobalMemoryStatus(&stat); 180 // Less than 5 % of virtual address space available 181 return stat.dwAvailVirtual < stat.dwTotalVirtual / 20; 182 } 183 } 184} 185else version (Darwin) 186{ 187 bool isLowOnMem(size_t mapped) nothrow @nogc 188 { 189 enum GB = 2 ^^ 30; 190 version (D_LP64) 191 return false; 192 else 193 { 194 // 80 % of available 4GB is used for GC (excluding malloc and mmap) 195 enum size_t limit = 4UL * GB * 8 / 10; 196 return mapped > limit; 197 } 198 } 199} 200else 201{ 202 bool isLowOnMem(size_t mapped) nothrow @nogc 203 { 204 enum GB = 2 ^^ 30; 205 version (D_LP64) 206 return false; 207 else 208 { 209 // be conservative and assume 3GB 210 enum size_t limit = 3UL * GB * 8 / 10; 211 return mapped > limit; 212 } 213 } 214} 215