]>
Commit | Line | Data |
---|---|---|
b4c522fa IB |
1 | /** |
2 | * This module contains a minimal garbage collector implementation according to | |
3 | * published requirements. This library is mostly intended to serve as an | |
4 | * example, but it is usable in applications which do not rely on a garbage | |
5 | * collector to clean up memory (ie. when dynamic array resizing is not used, | |
6 | * and all memory allocated with 'new' is freed deterministically with | |
7 | * 'delete'). | |
8 | * | |
9 | * Please note that block attribute data must be tracked, or at a minimum, the | |
10 | * FINALIZE bit must be tracked for any allocated memory block because calling | |
11 | * rt_finalize on a non-object block can result in an access violation. In the | |
12 | * allocator below, this tracking is done via a leading uint bitmask. A real | |
13 | * allocator may do better to store this data separately, similar to the basic | |
14 | * GC. | |
15 | * | |
16 | * Copyright: Copyright Sean Kelly 2005 - 2016. | |
5fee5ec3 | 17 | * License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0). |
b4c522fa IB |
18 | * Authors: Sean Kelly |
19 | */ | |
5fee5ec3 | 20 | module core.internal.gc.impl.manual.gc; |
b4c522fa | 21 | |
5fee5ec3 | 22 | import core.gc.gcinterface; |
b4c522fa | 23 | |
5fee5ec3 | 24 | import core.internal.container.array; |
b4c522fa IB |
25 | |
26 | import cstdlib = core.stdc.stdlib : calloc, free, malloc, realloc; | |
27 | static import core.memory; | |
28 | ||
29 | extern (C) void onOutOfMemoryError(void* pretend_sideffect = null) @trusted pure nothrow @nogc; /* dmd @@@BUG11461@@@ */ | |
30 | ||
5fee5ec3 IB |
31 | // register GC in C constructor (_STI_) |
32 | extern(C) pragma(crt_constructor) void _d_register_manual_gc() | |
b4c522fa | 33 | { |
5fee5ec3 IB |
34 | import core.gc.registry; |
35 | registerGCFactory("manual", &initialize); | |
36 | } | |
b4c522fa | 37 | |
5fee5ec3 IB |
38 | private GC initialize() |
39 | { | |
40 | import core.lifetime : emplace; | |
b4c522fa | 41 | |
5fee5ec3 IB |
42 | auto gc = cast(ManualGC) cstdlib.malloc(__traits(classInstanceSize, ManualGC)); |
43 | if (!gc) | |
44 | onOutOfMemoryError(); | |
b4c522fa | 45 | |
5fee5ec3 IB |
46 | return emplace(gc); |
47 | } | |
b4c522fa | 48 | |
5fee5ec3 IB |
49 | class ManualGC : GC |
50 | { | |
51 | Array!Root roots; | |
52 | Array!Range ranges; | |
b4c522fa IB |
53 | |
54 | this() | |
55 | { | |
56 | } | |
57 | ||
5fee5ec3 | 58 | ~this() |
b4c522fa | 59 | { |
5fee5ec3 IB |
60 | // TODO: cannot free as memory is overwritten and |
61 | // the monitor is still read in rt_finalize (called by destroy) | |
62 | // cstdlib.free(cast(void*) this); | |
b4c522fa IB |
63 | } |
64 | ||
65 | void enable() | |
66 | { | |
67 | } | |
68 | ||
69 | void disable() | |
70 | { | |
71 | } | |
72 | ||
73 | void collect() nothrow | |
74 | { | |
75 | } | |
76 | ||
77 | void collectNoStack() nothrow | |
78 | { | |
79 | } | |
80 | ||
81 | void minimize() nothrow | |
82 | { | |
83 | } | |
84 | ||
85 | uint getAttr(void* p) nothrow | |
86 | { | |
87 | return 0; | |
88 | } | |
89 | ||
90 | uint setAttr(void* p, uint mask) nothrow | |
91 | { | |
92 | return 0; | |
93 | } | |
94 | ||
95 | uint clrAttr(void* p, uint mask) nothrow | |
96 | { | |
97 | return 0; | |
98 | } | |
99 | ||
100 | void* malloc(size_t size, uint bits, const TypeInfo ti) nothrow | |
101 | { | |
102 | void* p = cstdlib.malloc(size); | |
103 | ||
104 | if (size && p is null) | |
105 | onOutOfMemoryError(); | |
106 | return p; | |
107 | } | |
108 | ||
5fee5ec3 | 109 | BlkInfo qalloc(size_t size, uint bits, const scope TypeInfo ti) nothrow |
b4c522fa IB |
110 | { |
111 | BlkInfo retval; | |
112 | retval.base = malloc(size, bits, ti); | |
113 | retval.size = size; | |
114 | retval.attr = bits; | |
115 | return retval; | |
116 | } | |
117 | ||
118 | void* calloc(size_t size, uint bits, const TypeInfo ti) nothrow | |
119 | { | |
120 | void* p = cstdlib.calloc(1, size); | |
121 | ||
122 | if (size && p is null) | |
123 | onOutOfMemoryError(); | |
124 | return p; | |
125 | } | |
126 | ||
127 | void* realloc(void* p, size_t size, uint bits, const TypeInfo ti) nothrow | |
128 | { | |
129 | p = cstdlib.realloc(p, size); | |
130 | ||
131 | if (size && p is null) | |
132 | onOutOfMemoryError(); | |
133 | return p; | |
134 | } | |
135 | ||
136 | size_t extend(void* p, size_t minsize, size_t maxsize, const TypeInfo ti) nothrow | |
137 | { | |
138 | return 0; | |
139 | } | |
140 | ||
141 | size_t reserve(size_t size) nothrow | |
142 | { | |
143 | return 0; | |
144 | } | |
145 | ||
5fee5ec3 | 146 | void free(void* p) nothrow @nogc |
b4c522fa IB |
147 | { |
148 | cstdlib.free(p); | |
149 | } | |
150 | ||
151 | /** | |
152 | * Determine the base address of the block containing p. If p is not a gc | |
153 | * allocated pointer, return null. | |
154 | */ | |
5fee5ec3 | 155 | void* addrOf(void* p) nothrow @nogc |
b4c522fa IB |
156 | { |
157 | return null; | |
158 | } | |
159 | ||
160 | /** | |
161 | * Determine the allocated size of pointer p. If p is an interior pointer | |
162 | * or not a gc allocated pointer, return 0. | |
163 | */ | |
5fee5ec3 | 164 | size_t sizeOf(void* p) nothrow @nogc |
b4c522fa IB |
165 | { |
166 | return 0; | |
167 | } | |
168 | ||
169 | /** | |
170 | * Determine the base address of the block containing p. If p is not a gc | |
171 | * allocated pointer, return null. | |
172 | */ | |
173 | BlkInfo query(void* p) nothrow | |
174 | { | |
175 | return BlkInfo.init; | |
176 | } | |
177 | ||
178 | core.memory.GC.Stats stats() nothrow | |
179 | { | |
180 | return typeof(return).init; | |
181 | } | |
182 | ||
5fee5ec3 IB |
183 | core.memory.GC.ProfileStats profileStats() nothrow |
184 | { | |
185 | return typeof(return).init; | |
186 | } | |
187 | ||
b4c522fa IB |
188 | void addRoot(void* p) nothrow @nogc |
189 | { | |
190 | roots.insertBack(Root(p)); | |
191 | } | |
192 | ||
193 | void removeRoot(void* p) nothrow @nogc | |
194 | { | |
195 | foreach (ref r; roots) | |
196 | { | |
197 | if (r is p) | |
198 | { | |
199 | r = roots.back; | |
200 | roots.popBack(); | |
201 | return; | |
202 | } | |
203 | } | |
204 | assert(false); | |
205 | } | |
206 | ||
207 | @property RootIterator rootIter() return @nogc | |
208 | { | |
209 | return &rootsApply; | |
210 | } | |
211 | ||
212 | private int rootsApply(scope int delegate(ref Root) nothrow dg) | |
213 | { | |
214 | foreach (ref r; roots) | |
215 | { | |
216 | if (auto result = dg(r)) | |
217 | return result; | |
218 | } | |
219 | return 0; | |
220 | } | |
221 | ||
222 | void addRange(void* p, size_t sz, const TypeInfo ti = null) nothrow @nogc | |
223 | { | |
224 | ranges.insertBack(Range(p, p + sz, cast() ti)); | |
225 | } | |
226 | ||
227 | void removeRange(void* p) nothrow @nogc | |
228 | { | |
229 | foreach (ref r; ranges) | |
230 | { | |
231 | if (r.pbot is p) | |
232 | { | |
233 | r = ranges.back; | |
234 | ranges.popBack(); | |
235 | return; | |
236 | } | |
237 | } | |
238 | assert(false); | |
239 | } | |
240 | ||
241 | @property RangeIterator rangeIter() return @nogc | |
242 | { | |
243 | return &rangesApply; | |
244 | } | |
245 | ||
246 | private int rangesApply(scope int delegate(ref Range) nothrow dg) | |
247 | { | |
248 | foreach (ref r; ranges) | |
249 | { | |
250 | if (auto result = dg(r)) | |
251 | return result; | |
252 | } | |
253 | return 0; | |
254 | } | |
255 | ||
5fee5ec3 | 256 | void runFinalizers(const scope void[] segment) nothrow |
b4c522fa IB |
257 | { |
258 | } | |
259 | ||
260 | bool inFinalizer() nothrow | |
261 | { | |
262 | return false; | |
263 | } | |
5fee5ec3 IB |
264 | |
265 | ulong allocatedInCurrentThread() nothrow | |
266 | { | |
267 | return typeof(return).init; | |
268 | } | |
b4c522fa | 269 | } |