]> git.llucax.com Git - software/dgc/cdgc.git/blob - gc/alloc.d
575095b30bbe457eaf9c6ab0f550ecd191e5975d
[software/dgc/cdgc.git] / gc / alloc.d
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
25  */
26
27 module gc.alloc;
28
29
30 // C OS-specific API
31
32 private extern (C) {
33     version (Win32) {
34         alias void* POINTER;
35         alias POINTER LPVOID;
36         alias uint DWORD;
37         alias int WINBOOL;
38         enum: DWORD {
39             PAGE_READWRITE = 4,
40             MEM_RESERVE = 8192,
41             MEM_COMMIT = 4096,
42             MEM_DECOMMIT = 16384,
43             MEM_RELEASE = 32768,
44         }
45         LPVOID VirtualAlloc(LPVOID, DWORD, DWORD, DWORD);
46         WINBOOL VirtualFree(LPVOID, DWORD, DWORD);
47     }
48     else version (Posix) {
49         version (linux) enum: bool { OPTIONAL_LARGEFILE_SUPPORT = true }
50         else version (solaris) enum: bool { OPTIONAL_LARGEFILE_SUPPORT = true }
51         else enum: bool { OPTIONAL_LARGEFILE_SUPPORT = false }
52         static if (OPTIONAL_LARGEFILE_SUPPORT)
53             enum: bool { USE_LARGEFILE64 = ((void*).sizeof == 4) }
54         else
55             enum: bool { USE_LARGEFILE64 = false }
56         static if (USE_LARGEFILE64 || (void*).sizeof > int.sizeof)
57             alias long off_t;
58         else
59             alias int off_t;
60         enum: int {
61             PROT_NONE = 0x0,
62             PROT_READ = 0x1,
63             PROT_WRITE = 0x2,
64             PROT_EXEC = 0x4,
65             MAP_SHARED = 0x01,
66             MAP_PRIVATE = 0x02,
67             MAP_FIXED = 0x10,
68         }
69         const MAP_FAILED = cast(void*) -1;
70         // Non-standard, but needed
71         version (linux) { enum: int { MAP_ANON = 0x20 } }
72         else version (darwin) { enum: int { MAP_ANON = 0x1000 } }
73         else version (freebsd) { enum: int { MAP_ANON = 0x1000 } }
74         else version (solaris) { enum: int { MAP_ANON = 0x100 } }
75         void* mmap(void*, size_t, int, int, int, off_t);
76         int munmap(void*, size_t);
77     }
78     else {
79         // Standard C library
80         import gc.libc;
81     }
82 }
83
84
85 // Public interface
86
87 version (D_Ddoc)
88 {
89     /**
90      * Map memory.
91      */
92     void* os_mem_map(size_t nbytes);
93
94     /**
95      * Commit memory.
96      * Returns:
97      *      true  success
98      *      false failure
99      */
100     bool os_mem_commit(void* base, size_t offset, size_t nbytes);
101
102     /**
103      * Decommit memory.
104      * Returns:
105      *      true  success
106      *      false failure
107      */
108     bool os_mem_decommit(void* base, size_t offset, size_t nbytes);
109
110     /**
111      * Unmap memory allocated with os_mem_map().
112      * Memory must have already been decommitted.
113      * Returns:
114      *      true  success
115      *      false failure
116      */
117     bool os_mem_unmap(void* base, size_t nbytes);
118 }
119 // Implementations
120 else static if (is(typeof(VirtualAlloc)))
121 {
122     void* os_mem_map(size_t nbytes)
123     {
124         return VirtualAlloc(null, nbytes, MEM_RESERVE, PAGE_READWRITE);
125     }
126
127     bool os_mem_commit(void* base, size_t offset, size_t nbytes)
128     {
129         void* p = VirtualAlloc(base + offset, nbytes, MEM_COMMIT, PAGE_READWRITE);
130         return p !is null;
131     }
132
133     bool os_mem_decommit(void* base, size_t offset, size_t nbytes)
134     {
135         return VirtualFree(base + offset, nbytes, MEM_DECOMMIT) != 0;
136     }
137
138     bool os_mem_unmap(void* base, size_t nbytes)
139     {
140         return VirtualFree(base, 0, MEM_RELEASE) != 0;
141     }
142 }
143 else static if (is(typeof(mmap)) && is(typeof(MAP_ANON)))
144 {
145     void* os_mem_map(size_t nbytes)
146     {
147         void* p = mmap(null, nbytes,
148                 PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
149         return (p == MAP_FAILED) ? null : p;
150     }
151
152     bool os_mem_commit(void* base, size_t offset, size_t nbytes)
153     {
154         return true;
155     }
156
157     bool os_mem_decommit(void* base, size_t offset, size_t nbytes)
158     {
159         return true;
160     }
161
162     bool os_mem_unmap(void* base, size_t nbytes)
163     {
164         return munmap(base, nbytes) == 0;
165     }
166 }
167 else static if (is(typeof(malloc)))
168 {
169     // NOTE: This assumes malloc granularity is at least (void*).sizeof.  If
170     //       (req_size + PAGESIZE) is allocated, and the pointer is rounded up
171     //       to PAGESIZE alignment, there will be space for a void* at the end
172     //       after PAGESIZE bytes used by the GC.
173
174     import gcx; // for PAGESIZE
175
176     const size_t PAGE_MASK = PAGESIZE - 1;
177
178     void* os_mem_map(size_t nbytes)
179     {
180         byte* p, q;
181         p = cast(byte* ) malloc(nbytes + PAGESIZE);
182         q = p + ((PAGESIZE - ((cast(size_t) p & PAGE_MASK))) & PAGE_MASK);
183         *cast(void**)(q + nbytes) = p;
184         return q;
185     }
186
187     bool os_mem_commit(void* base, size_t offset, size_t nbytes)
188     {
189         return true;
190     }
191
192     bool os_mem_decommit(void* base, size_t offset, size_t nbytes)
193     {
194         return true;
195     }
196
197     bool os_mem_unmap(void* base, size_t nbytes)
198     {
199         free(*cast(void**)(cast(byte*) base + nbytes));
200         return true;
201     }
202 }
203 else
204 {
205     static assert(false, "No supported allocation methods available.");
206 }