1 /*******************************************************************************
2 
3     Interface and GC / malloc implementations of a memory manager which can
4     create and destroy chunks of memory.
5 
6     Copyright:
7         Copyright (c) 2009-2016 dunnhumby Germany GmbH.
8         All rights reserved.
9 
10     License:
11         Boost Software License Version 1.0. See LICENSE_BOOST.txt for details.
12         Alternatively, this file may be distributed under the terms of the Tango
13         3-Clause BSD License (see LICENSE_BSD.txt for details).
14 
15 *******************************************************************************/
16 
17 module ocean.util.container.mem.MemManager;
18 
19 import core.memory;
20 import core.stdc.stdlib : malloc, free;
21 
22 import ocean.core.Enforce;
23 import ocean.core.ExceptionDefinitions : onOutOfMemoryError;
24 import ocean.meta.types.Qualifiers;
25 
26 /*******************************************************************************
27 
28     C Malloc memory manager instance,
29     not scanned by the gc for pointers/references
30 
31 *******************************************************************************/
32 
33 __gshared IMemManager noScanMallocMemManager;
34 
35 
36 /*******************************************************************************
37 
38     C Malloc memory manager instance, scanned by the gc for pointers/references
39 
40 *******************************************************************************/
41 
42 __gshared IMemManager mallocMemManager;
43 
44 
45 /*******************************************************************************
46 
47     GC memory manager instance,
48     not scanned by the gc for pointers/references
49 
50 *******************************************************************************/
51 
52 __gshared IMemManager noScanGcMemManager;
53 
54 
55 /*******************************************************************************
56 
57     GC memory manager instance, scanned by the gc for pointers/references
58 
59 *******************************************************************************/
60 
61 __gshared IMemManager gcMemManager;
62 
63 shared static this ( )
64 {
65     noScanMallocMemManager = new MallocMemManager!(false);
66     noScanGcMemManager     = new GCMemManager!(false);
67     mallocMemManager       = new MallocMemManager!(true);
68     gcMemManager           = new GCMemManager!(true);
69 }
70 
71 /*******************************************************************************
72 
73     Memory manager interface.
74 
75 *******************************************************************************/
76 
77 public interface IMemManager
78 {
79     /***************************************************************************
80 
81         Allocates a buffer of the specified dimension.
82 
83         Params:
84             dimension = bytes to allocate
85 
86         Returns:
87             new buffer
88 
89     ***************************************************************************/
90 
91     public ubyte[] create ( size_t dimension );
92 
93 
94     /***************************************************************************
95 
96         Explicit deallocation
97 
98         Note that it is up to the user of classes which implement this interface
99         to ensure that the buffer passed was in fact allocated by the same
100         instance.
101 
102         Params:
103             buffer = buffer to deallocate
104 
105     ***************************************************************************/
106 
107     public void destroy ( ubyte[] buffer );
108 
109     /***************************************************************************
110 
111         Destructor compatible deallocation
112 
113         Note that it is up to the user of classes which implement this interface
114         to ensure that the buffer passed was in fact allocated by the same
115         instance.
116 
117         The destructor is always called when an object is collected or when it
118         is explicitly deleted. This method is intended to be called from the
119         destructor.
120 
121         Params:
122             buffer = buffer to cleanup
123 
124     ***************************************************************************/
125 
126     public void dtor ( ubyte[] buffer );
127 }
128 
129 
130 
131 /*******************************************************************************
132 
133     Memory manager implementation using the D garbage collector.
134 
135     Params:
136         gc_aware  = whether the gc should scan the allocated memory for
137                     pointers or references
138 
139 *******************************************************************************/
140 
141 private class GCMemManager ( bool gc_aware ) : IMemManager
142 {
143     /***************************************************************************
144 
145         Allocates a buffer of the specified dimension via the GC.
146 
147         Params:
148             dimension = bytes to allocate
149 
150         Returns:
151             new buffer
152 
153     ***************************************************************************/
154 
155     public override ubyte[] create ( size_t dimension )
156     {
157         static if ( gc_aware )
158         {
159             return cast(ubyte[]) new void[dimension];
160         }
161         else
162         {
163             return new ubyte[dimension];
164         }
165     }
166 
167 
168     /***************************************************************************
169 
170         Explicit deallocation
171 
172         Note that it is up to the user of classes which implement this interface
173         to ensure that the buffer passed was in fact allocated by the same
174         instance.
175 
176         Params:
177             buffer = buffer to deallocate
178 
179     ***************************************************************************/
180 
181     public override void destroy ( ubyte[] buffer )
182     {
183         import core.memory;
184         GC.free(buffer.ptr);
185     }
186 
187     /***************************************************************************
188 
189         Destructor compatible deallocation
190 
191         Note that it is up to the user of classes which implement this interface
192         to ensure that the buffer passed was in fact allocated by the same
193         instance.
194 
195         The destructor is always called when an object is collected or when it
196         is explicitly deleted. This method is intended to be called from the
197         destructor.
198 
199         Params:
200             buffer = buffer to cleanup
201 
202     ***************************************************************************/
203 
204     public override void dtor ( ubyte[] buffer )
205     {
206     }
207 }
208 
209 
210 
211 /*******************************************************************************
212 
213     Memory manager implementation using malloc and free.
214 
215     Template Parameters:
216         gc_aware  = whether the gc should scan the allocated memory for
217                     pointers or references
218 
219 *******************************************************************************/
220 
221 private class MallocMemManager ( bool gc_aware ) : IMemManager
222 {
223     /***************************************************************************
224 
225         Allocates a buffer of the specified dimension using malloc.
226 
227         Params:
228             dimension = bytes to allocate
229 
230         Returns:
231             new buffer
232 
233     ***************************************************************************/
234 
235     public override ubyte[] create ( size_t dimension )
236     {
237         auto ptr = cast(ubyte*)malloc(dimension);
238         if (ptr is null)
239         {
240             onOutOfMemoryError();
241         }
242 
243         static if ( gc_aware )
244         {
245             GC.addRange(ptr, dimension);
246         }
247 
248         return ptr[0..dimension];
249     }
250 
251 
252     /***************************************************************************
253 
254         Explicit deallocation
255 
256         Note that it is up to the user of classes which implement this interface
257         to ensure that the buffer passed was in fact allocated by the same
258         instance.
259 
260         Params:
261             buffer = buffer to deallocate
262 
263     ***************************************************************************/
264 
265     public override void destroy ( ubyte[] buffer )
266     {
267         if ( buffer.ptr !is null )
268         {
269             static if ( gc_aware )
270             {
271                 GC.removeRange(buffer.ptr);
272             }
273 
274             free(buffer.ptr);
275         }
276     }
277 
278     /***************************************************************************
279 
280         Destructor compatible deallocation
281 
282         Note that it is up to the user of classes which implement this interface
283         to ensure that the buffer passed was in fact allocated by the same
284         instance.
285 
286         The destructor is always called when an object is collected or when it
287         is explicitly deleted. This method is intended to be called from the
288         destructor.
289 
290         Params:
291             buffer = buffer to cleanup
292 
293     ***************************************************************************/
294 
295     public override void dtor ( ubyte[] buffer )
296     {
297         if ( buffer.ptr !is null )
298         {
299             static if ( gc_aware )
300             {
301                 GC.removeRange(buffer.ptr);
302             }
303 
304             free(buffer.ptr);
305         }
306     }
307 }