1 /** 2 * This module contains allocation functions for the garbage collector. 3 * 4 * Copyright: Copyright (C) 2005-2006 Digital Mars, www.digitalmars.com. 5 * All rights reserved. 6 * License: 7 * This software is provided 'as-is', without any express or implied 8 * warranty. In no event will the authors be held liable for any damages 9 * arising from the use of this software. 10 * 11 * Permission is granted to anyone to use this software for any purpose, 12 * including commercial applications, and to alter it and redistribute it 13 * freely, in both source and binary form, subject to the following 14 * restrictions: 15 * 16 * o The origin of this software must not be misrepresented; you must not 17 * claim that you wrote the original software. If you use this software 18 * in a product, an acknowledgment in the product documentation would be 19 * appreciated but is not required. 20 * o Altered source versions must be plainly marked as such, and must not 21 * be misrepresented as being the original software. 22 * o This notice may not be removed or altered from any source 23 * distribution. 24 * Authors: Walter Bright, David Friedman, Sean Kelly, Leandro Lucarella 25 */ 26 27 module rt.gc.cdgc.os; 28 29 30 // Fork 31 //////////////////////////////////////////////////////////////////////// 32 33 // Public interface/Documentation 34 35 /** 36 * Possible results for the wait_pid() function. 37 */ 38 enum WRes 39 { 40 DONE, /// The process has finished successfully 41 RUNNING, /// The process is still running 42 ERROR /// There was an error waiting for the process 43 } 44 45 version (D_Ddoc) { 46 47 /** 48 * Indicates if an implementation support fork(). 49 * 50 * The value shown here is just demostrative, the real value is defined based 51 * on the OS it's being compiled in. 52 */ 53 const HAVE_FORK = true; 54 55 /** 56 * Wait for a process with PID pid to finish. 57 * 58 * If block is false, this function will not block, and return WRes.RUNNING if 59 * the process is still running. Otherwise it will return always WRes.DONE 60 * (unless there is an error, in which case WRes.ERROR is returned). 61 */ 62 WRes wait_pid(pid_t pid, bool block = true); 63 64 public import tango.stdc.posix.unistd: pid_t, fork; 65 66 } 67 68 // Implementations 69 else version (Posix) { 70 enum { HAVE_FORK = true } 71 public import tango.stdc.posix.unistd: pid_t, fork; 72 import tango.stdc.posix.sys.wait: waitpid, WNOHANG; 73 public WRes wait_pid(pid_t pid, bool block = true) { 74 int status = void; 75 pid_t waited_pid = waitpid(pid, &status, block ? 0 : WNOHANG); 76 if (waited_pid == 0) 77 return WRes.RUNNING; 78 assert (waited_pid == pid); 79 assert (status == 0); 80 if (waited_pid != pid || status != 0) 81 return WRes.ERROR; 82 return WRes.DONE; 83 } 84 } 85 86 else { 87 enum { HAVE_FORK = false } 88 alias int pid_t; 89 pid_t fork() { assert (false); return -1; } 90 WRes wait_pid(pid_t, bool = true) { assert (false); return false; } 91 } 92 93 94 // Allocation 95 //////////////////////////////////////////////////////////////////////// 96 97 version (Win32) 98 import tango.sys.win32.UserGdi; 99 else version (Posix) 100 import tango.stdc.posix.sys.mman; 101 else 102 import tango.stdc.stdlib; 103 104 105 // Public interface/Documentation 106 107 /** 108 * Visibility of the mapped memory. 109 */ 110 enum Vis 111 { 112 PRIV, /// Private to this process 113 SHARED, /// Shared across fork()ed processes (only when HAVE_SHARED) 114 } 115 116 version (D_Ddoc) { 117 118 /** 119 * Indicates if an implementation support mapping shared memory. 120 * 121 * The value shown here is just demostrative, the real value is defined based 122 * on the OS it's being compiled in. 123 */ 124 const HAVE_SHARED = false; 125 126 /** 127 * Map memory. 128 */ 129 void* alloc(size_t nbytes, Vis vis = Vis.PRIV); 130 131 /** 132 * Unmap memory allocated with alloc(). 133 * Returns: 134 * true success 135 * false failure 136 */ 137 bool dealloc(void* base, size_t nbytes, Vis vis = Vis.PRIV); 138 139 } 140 141 // Implementations 142 else static if (is(typeof(VirtualAlloc))) { 143 enum { HAVE_SHARED = false } 144 145 void* alloc(size_t nbytes, Vis vis = Vis.PRIV) 146 { 147 assert (vis == Vis.PRIV); 148 return VirtualAlloc(null, nbytes, MEM_RESERVE | MEM_COMMIT, 149 PAGE_READWRITE); 150 } 151 152 bool dealloc(void* base, size_t nbytes, Vis vis = Vis.PRIV) 153 { 154 assert (vis == Vis.PRIV); 155 return VirtualFree(base, 0, MEM_RELEASE) != 0; 156 } 157 158 } 159 160 else static if (is(typeof(mmap)) && is(typeof(MAP_ANON))) { 161 enum { HAVE_SHARED = true } 162 163 void* alloc(size_t nbytes, Vis vis = Vis.PRIV) 164 { 165 auto flags = MAP_ANON; 166 if (vis == Vis.SHARED) 167 flags |= MAP_SHARED; 168 else // PRIV 169 flags |= MAP_PRIVATE; 170 void* p = mmap(null, nbytes, PROT_READ | PROT_WRITE, flags, -1, 0); 171 return (p == MAP_FAILED) ? null : p; 172 } 173 174 bool dealloc(void* base, size_t nbytes, Vis vis = Vis.PRIV) 175 { 176 // vis is not necessary to unmap 177 return munmap(base, nbytes) == 0; 178 } 179 } 180 181 else static if (is(typeof(malloc))) { 182 enum { HAVE_SHARED = false } 183 184 // NOTE: This assumes malloc granularity is at least (void*).sizeof. If 185 // (req_size + PAGESIZE) is allocated, and the pointer is rounded up 186 // to PAGESIZE alignment, there will be space for a void* at the end 187 // after PAGESIZE bytes used by the GC. 188 189 import rt.gc.cdgc.gc: PAGESIZE; 190 191 const size_t PAGE_MASK = PAGESIZE - 1; 192 193 void* alloc(size_t nbytes, Vis vis = Vis.PRIV) 194 { 195 assert (vis == Vis.PRIV); 196 byte* p, q; 197 p = cast(byte* ) malloc(nbytes + PAGESIZE); 198 q = p + ((PAGESIZE - ((cast(size_t) p & PAGE_MASK))) & PAGE_MASK); 199 *cast(void**)(q + nbytes) = p; 200 return q; 201 } 202 203 bool dealloc(void* base, size_t nbytes, Vis vis = Vis.PRIV) 204 { 205 assert (vis == Vis.PRIV); 206 free(*cast(void**)(cast(byte*) base + nbytes)); 207 return true; 208 } 209 } 210 211 else static assert(false, "No supported allocation methods available."); 212 213 214 // vim: set et sw=4 sts=4 :