1 /* Copyright (C) 2001-2012 Artifex Software, Inc.
2 All Rights Reserved.
3
4 This software is provided AS-IS with no warranty, either express or
5 implied.
6
7 This software is distributed under license and may not be copied,
8 modified or distributed except as expressly authorized under the terms
9 of the license contained in the file LICENSE in this distribution.
10
11 Refer to licensing information at http://www.artifex.com or contact
12 Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134, San Rafael,
13 CA 94903, U.S.A., +1(415)492-9861, for further information.
14 */
15
16
17 /* Monitor-locked heap memory allocator */
18
19 /* Initial version 2/1/98 by John Desrosiers (soho@crl.com) */
20 /* Revised 8/6/98 by L. Peter Deutsch (ghost@aladdin.com) for changes */
21 /* in memory manager API */
22 /* Edited 3/23/1999 by L. Peter Deutsch to remove compiler warnings. */
23
24 #include "gx.h"
25 #include "gsmemlok.h"
26 #include "gserrors.h"
27
28 /* Raw memory procedures */
29 static gs_memory_proc_alloc_bytes(gs_locked_alloc_bytes_immovable);
30 static gs_memory_proc_resize_object(gs_locked_resize_object);
31 static gs_memory_proc_free_object(gs_locked_free_object);
32 static gs_memory_proc_stable(gs_locked_stable);
33 static gs_memory_proc_status(gs_locked_status);
34 static gs_memory_proc_free_all(gs_locked_free_all);
35 static gs_memory_proc_consolidate_free(gs_locked_consolidate_free);
36
37 /* Object memory procedures */
38 static gs_memory_proc_alloc_bytes(gs_locked_alloc_bytes);
39 static gs_memory_proc_alloc_struct(gs_locked_alloc_struct);
40 static gs_memory_proc_alloc_struct(gs_locked_alloc_struct_immovable);
41 static gs_memory_proc_alloc_byte_array(gs_locked_alloc_byte_array);
42 static gs_memory_proc_alloc_byte_array(gs_locked_alloc_byte_array_immovable);
43 static gs_memory_proc_alloc_struct_array(gs_locked_alloc_struct_array);
44 static gs_memory_proc_alloc_struct_array(gs_locked_alloc_struct_array_immovable);
45 static gs_memory_proc_object_size(gs_locked_object_size);
46 static gs_memory_proc_object_type(gs_locked_object_type);
47 static gs_memory_proc_alloc_string(gs_locked_alloc_string);
48 static gs_memory_proc_alloc_string(gs_locked_alloc_string_immovable);
49 static gs_memory_proc_resize_string(gs_locked_resize_string);
50 static gs_memory_proc_free_string(gs_locked_free_string);
51 static gs_memory_proc_register_root(gs_locked_register_root);
52 static gs_memory_proc_unregister_root(gs_locked_unregister_root);
53 static gs_memory_proc_enable_free(gs_locked_enable_free);
54 static const gs_memory_procs_t locked_procs =
55 {
56 /* Raw memory procedures */
57 gs_locked_alloc_bytes_immovable,
58 gs_locked_resize_object,
59 gs_locked_free_object,
60 gs_locked_stable,
61 gs_locked_status,
62 gs_locked_free_all,
63 gs_locked_consolidate_free,
64 /* Object memory procedures */
65 gs_locked_alloc_bytes,
66 gs_locked_alloc_struct,
67 gs_locked_alloc_struct_immovable,
68 gs_locked_alloc_byte_array,
69 gs_locked_alloc_byte_array_immovable,
70 gs_locked_alloc_struct_array,
71 gs_locked_alloc_struct_array_immovable,
72 gs_locked_object_size,
73 gs_locked_object_type,
74 gs_locked_alloc_string,
75 gs_locked_alloc_string_immovable,
76 gs_locked_resize_string,
77 gs_locked_free_string,
78 gs_locked_register_root,
79 gs_locked_unregister_root,
80 gs_locked_enable_free
81 };
82
83 /* ---------- Public constructors/destructors ---------- */
84
85 /* Initialize a gs_memory_locked_t */
86 int /* -ve error code or 0 */
gs_memory_locked_init(gs_memory_locked_t * lmem,gs_memory_t * target)87 gs_memory_locked_init(
88 gs_memory_locked_t * lmem, /* allocator to init */
89 gs_memory_t * target /* allocator to monitor lock */
90 )
91 {
92 lmem->stable_memory = 0;
93 lmem->procs = locked_procs;
94 lmem->target = target;
95 lmem->gs_lib_ctx = target->gs_lib_ctx;
96 lmem->non_gc_memory = (gs_memory_t *)lmem; /* WRONG: THIS IS QUESTIONABLE since this will not */
97 /* be non_gc_memory if the target was a GC memory */
98 lmem->thread_safe_memory = (gs_memory_t *)lmem; /* this allocator is thread safe */
99
100 /* Allocate a monitor to serialize access to structures within */
101 lmem->monitor = gx_monitor_alloc(target);
102 return (lmem->monitor ? 0 : gs_note_error(gs_error_VMerror));
103 }
104
105 /* Release a locked memory manager. */
106 /* Note that this has no effect on the target. */
107 void
gs_memory_locked_release(gs_memory_locked_t * lmem)108 gs_memory_locked_release(gs_memory_locked_t *lmem)
109 {
110 gs_memory_free_all((gs_memory_t *)lmem, FREE_ALL_STRUCTURES,
111 "gs_memory_locked_release");
112 gx_monitor_free(lmem->monitor);
113 }
114
115 /* ---------- Accessors ------------- */
116
117 /* Retrieve this allocator's target */
118 gs_memory_t *
gs_memory_locked_target(const gs_memory_locked_t * lmem)119 gs_memory_locked_target(const gs_memory_locked_t *lmem)
120 {
121 return lmem->target;
122 }
123
124 /* -------- Private members just wrap a monitor around a gs_memory_heap --- */
125
126 /*
127 * Contrary to our usual practice, we don't use BEGIN/END here, because
128 * that causes some compilers to give bogus error messages.
129 */
130
131 #define DO_MONITORED(call_target)\
132 gs_memory_locked_t * const lmem = (gs_memory_locked_t *)mem;\
133 \
134 gx_monitor_enter(lmem->monitor);\
135 call_target;\
136 gx_monitor_leave(lmem->monitor)
137
138 #define RETURN_MONITORED(result_type, call_target)\
139 gs_memory_locked_t * const lmem = (gs_memory_locked_t *)mem;\
140 result_type temp;\
141 \
142 gx_monitor_enter(lmem->monitor);\
143 temp = call_target;\
144 gx_monitor_leave(lmem->monitor);\
145 return temp
146
147 /* Procedures */
148 static void
gs_locked_free_all(gs_memory_t * mem,uint free_mask,client_name_t cname)149 gs_locked_free_all(gs_memory_t * mem, uint free_mask, client_name_t cname)
150 {
151 gs_memory_locked_t * const lmem = (gs_memory_locked_t *)mem;
152 gs_memory_t * const target = lmem->target;
153
154 /* Only free the structures and the allocator itself. */
155 if (mem->stable_memory) {
156 if (mem->stable_memory != mem)
157 gs_memory_free_all(mem->stable_memory, free_mask, cname);
158 if (free_mask & FREE_ALL_ALLOCATOR)
159 mem->stable_memory = 0;
160 }
161 if (free_mask & FREE_ALL_STRUCTURES) {
162 /*
163 * Check for monitor == 0, in case this is called after a
164 * failure during initialization.
165 */
166 if (lmem->monitor)
167 gx_monitor_free(lmem->monitor);
168 lmem->monitor = 0;
169 lmem->target = 0;
170 }
171 if (free_mask & FREE_ALL_ALLOCATOR)
172 gs_free_object(target, lmem, cname);
173 }
174 static void
gs_locked_consolidate_free(gs_memory_t * mem)175 gs_locked_consolidate_free(gs_memory_t * mem)
176 {
177 DO_MONITORED(
178 (*lmem->target->procs.consolidate_free)(lmem->target)
179 );
180 }
181 static byte *
gs_locked_alloc_bytes(gs_memory_t * mem,uint size,client_name_t cname)182 gs_locked_alloc_bytes(gs_memory_t * mem, uint size, client_name_t cname)
183 {
184 RETURN_MONITORED(
185 byte *,
186 (*lmem->target->procs.alloc_bytes)
187 (lmem->target, size, cname)
188 );
189 }
190 static byte *
gs_locked_alloc_bytes_immovable(gs_memory_t * mem,uint size,client_name_t cname)191 gs_locked_alloc_bytes_immovable(gs_memory_t * mem, uint size,
192 client_name_t cname)
193 {
194 RETURN_MONITORED(
195 byte *,
196 (*lmem->target->procs.alloc_bytes_immovable)
197 (lmem->target, size, cname)
198 );
199 }
200 static void *
gs_locked_alloc_struct(gs_memory_t * mem,gs_memory_type_ptr_t pstype,client_name_t cname)201 gs_locked_alloc_struct(gs_memory_t * mem, gs_memory_type_ptr_t pstype,
202 client_name_t cname)
203 {
204 RETURN_MONITORED(
205 void *,
206 (*lmem->target->procs.alloc_struct)
207 (lmem->target, pstype, cname)
208 );
209 }
210 static void *
gs_locked_alloc_struct_immovable(gs_memory_t * mem,gs_memory_type_ptr_t pstype,client_name_t cname)211 gs_locked_alloc_struct_immovable(gs_memory_t * mem,
212 gs_memory_type_ptr_t pstype, client_name_t cname)
213 {
214 RETURN_MONITORED(
215 void *,
216 (*lmem->target->procs.alloc_struct_immovable)
217 (lmem->target, pstype, cname)
218 );
219 }
220 static byte *
gs_locked_alloc_byte_array(gs_memory_t * mem,uint num_elements,uint elt_size,client_name_t cname)221 gs_locked_alloc_byte_array(gs_memory_t * mem, uint num_elements, uint elt_size,
222 client_name_t cname)
223 {
224 RETURN_MONITORED(
225 byte *,
226 (*lmem->target->procs.alloc_byte_array)
227 (lmem->target, num_elements, elt_size, cname)
228 );
229 }
230 static byte *
gs_locked_alloc_byte_array_immovable(gs_memory_t * mem,uint num_elements,uint elt_size,client_name_t cname)231 gs_locked_alloc_byte_array_immovable(gs_memory_t * mem, uint num_elements,
232 uint elt_size, client_name_t cname)
233 {
234 RETURN_MONITORED(
235 byte *,
236 (*lmem->target->procs.alloc_byte_array_immovable)
237 (lmem->target, num_elements, elt_size, cname)
238 );
239 }
240 static void *
gs_locked_alloc_struct_array(gs_memory_t * mem,uint num_elements,gs_memory_type_ptr_t pstype,client_name_t cname)241 gs_locked_alloc_struct_array(gs_memory_t * mem, uint num_elements,
242 gs_memory_type_ptr_t pstype, client_name_t cname)
243 {
244 RETURN_MONITORED(
245 void *,
246 (*lmem->target->procs.alloc_struct_array)
247 (lmem->target, num_elements, pstype, cname)
248 );
249 }
250 static void *
gs_locked_alloc_struct_array_immovable(gs_memory_t * mem,uint num_elements,gs_memory_type_ptr_t pstype,client_name_t cname)251 gs_locked_alloc_struct_array_immovable(gs_memory_t * mem, uint num_elements,
252 gs_memory_type_ptr_t pstype, client_name_t cname)
253 {
254 RETURN_MONITORED(
255 void *,
256 (*lmem->target->procs.alloc_struct_array_immovable)
257 (lmem->target, num_elements, pstype, cname)
258 );
259 }
260 static void *
gs_locked_resize_object(gs_memory_t * mem,void * obj,uint new_num_elements,client_name_t cname)261 gs_locked_resize_object(gs_memory_t * mem, void *obj, uint new_num_elements,
262 client_name_t cname)
263 {
264 RETURN_MONITORED(
265 void *,
266 (*lmem->target->procs.resize_object)
267 (lmem->target, obj, new_num_elements, cname)
268 );
269 }
270 static uint
gs_locked_object_size(gs_memory_t * mem,const void * ptr)271 gs_locked_object_size(gs_memory_t * mem, const void *ptr)
272 {
273 RETURN_MONITORED(
274 uint,
275 (*lmem->target->procs.object_size)
276 (lmem->target, ptr)
277 );
278 }
279 static gs_memory_type_ptr_t
gs_locked_object_type(const gs_memory_t * mem,const void * ptr)280 gs_locked_object_type(const gs_memory_t * mem, const void *ptr)
281 {
282 RETURN_MONITORED(
283 gs_memory_type_ptr_t,
284 (*lmem->target->procs.object_type)
285 (lmem->target, ptr)
286 );
287 }
288 static void
gs_locked_free_object(gs_memory_t * mem,void * ptr,client_name_t cname)289 gs_locked_free_object(gs_memory_t * mem, void *ptr, client_name_t cname)
290 {
291 DO_MONITORED(
292 (*lmem->target->procs.free_object)
293 (lmem->target, ptr, cname)
294 );
295 }
296 static byte *
gs_locked_alloc_string(gs_memory_t * mem,uint nbytes,client_name_t cname)297 gs_locked_alloc_string(gs_memory_t * mem, uint nbytes, client_name_t cname)
298 {
299 RETURN_MONITORED(
300 byte *,
301 (*lmem->target->procs.alloc_string)
302 (lmem->target, nbytes, cname)
303 );
304 }
305 static byte *
gs_locked_alloc_string_immovable(gs_memory_t * mem,uint nbytes,client_name_t cname)306 gs_locked_alloc_string_immovable(gs_memory_t * mem, uint nbytes,
307 client_name_t cname)
308 {
309 RETURN_MONITORED(
310 byte *,
311 (*lmem->target->procs.alloc_string_immovable)
312 (lmem->target, nbytes, cname)
313 );
314 }
315 static byte *
gs_locked_resize_string(gs_memory_t * mem,byte * data,uint old_num,uint new_num,client_name_t cname)316 gs_locked_resize_string(gs_memory_t * mem, byte * data, uint old_num,
317 uint new_num,
318 client_name_t cname)
319 {
320 RETURN_MONITORED(
321 byte *,
322 (*lmem->target->procs.resize_string)
323 (lmem->target, data, old_num, new_num, cname)
324 );
325 }
326 static void
gs_locked_free_string(gs_memory_t * mem,byte * data,uint nbytes,client_name_t cname)327 gs_locked_free_string(gs_memory_t * mem, byte * data, uint nbytes,
328 client_name_t cname)
329 {
330 DO_MONITORED(
331 (*lmem->target->procs.free_string)
332 (lmem->target, data, nbytes, cname)
333 );
334 }
335 static int
gs_locked_register_root(gs_memory_t * mem,gs_gc_root_t * rp,gs_ptr_type_t ptype,void ** up,client_name_t cname)336 gs_locked_register_root(gs_memory_t * mem, gs_gc_root_t * rp,
337 gs_ptr_type_t ptype, void **up, client_name_t cname)
338 {
339 RETURN_MONITORED(
340 int,
341 (*lmem->target->procs.register_root)
342 (lmem->target, rp, ptype, up, cname)
343 );
344 }
345 static void
gs_locked_unregister_root(gs_memory_t * mem,gs_gc_root_t * rp,client_name_t cname)346 gs_locked_unregister_root(gs_memory_t * mem, gs_gc_root_t * rp,
347 client_name_t cname)
348 {
349 DO_MONITORED(
350 (*lmem->target->procs.unregister_root)
351 (lmem->target, rp, cname)
352 );
353 }
354 static gs_memory_t *
gs_locked_stable(gs_memory_t * mem)355 gs_locked_stable(gs_memory_t * mem)
356 {
357 if (!mem->stable_memory) {
358 gs_memory_locked_t * const lmem = (gs_memory_locked_t *)mem;
359 gs_memory_t *stable;
360
361 gx_monitor_enter(lmem->monitor);
362 stable = gs_memory_stable(lmem->target);
363 if (stable == lmem->target)
364 mem->stable_memory = mem;
365 else {
366 gs_memory_locked_t *locked_stable = (gs_memory_locked_t *)
367 gs_alloc_bytes(stable, sizeof(*lmem), "gs_locked_stable");
368
369 if (locked_stable) {
370 int code = gs_memory_locked_init(locked_stable, stable);
371
372 if (code < 0)
373 gs_free_object(stable, locked_stable, "gs_locked_stable");
374 else
375 mem->stable_memory = (gs_memory_t *)locked_stable;
376 }
377 }
378 gx_monitor_leave(lmem->monitor);
379 }
380 return mem->stable_memory;
381 }
382 static void
gs_locked_status(gs_memory_t * mem,gs_memory_status_t * pstat)383 gs_locked_status(gs_memory_t * mem, gs_memory_status_t * pstat)
384 {
385 DO_MONITORED(
386 (*lmem->target->procs.status)(lmem->target, pstat)
387 );
388 pstat->is_thread_safe = true; /* the monitor (mutex) makes this thread safe */
389 }
390 static void
gs_locked_enable_free(gs_memory_t * mem,bool enable)391 gs_locked_enable_free(gs_memory_t * mem, bool enable)
392 {
393 DO_MONITORED(
394 (*lmem->target->procs.enable_free)(lmem->target, enable)
395 );
396 }
397